JTable removing row gives ArrayOutofBounds exception -1

indexoutofboundsexception, java, jtable, swing, tablemodel

Solution

You are changing the TableModel inside of a TableModelListener and that seems just a bit risky to me and is a risk for unwanted recursion. I would re-factor your code so as not to do this if possible. If you're still stuck, then you should create and post an sscce.

Edit 1

If I make an sscce out of your code and add println statements:

import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.*;
import javax.swing.table.*;

public class ExpenditurePanel extends JPanel implements TableModelListener {

   private static final long serialVersionUID = 1L;
   private static TableModel1 model;
   private JTable table;

   public ExpenditurePanel() {
      model = new TableModel1();
      table = new JTable(model);
      table.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null,
            null));
      table.setRowSelectionAllowed(false);
      table.setFillsViewportHeight(true);
      table.setCellSelectionEnabled(true);
      table.setColumnSelectionAllowed(false);

      model.addColumn("Name");
      model.addColumn("Week");
      model.addColumn("Fortnight");
      model.addColumn("Month");
      model.addColumn("Year");
      model.addColumn("Remove");

      Object[] default1 = { "Accomodation", "", "", "", "", false };
      Object[] default2 = { "Food", "", "", "", "", false };

      model.addRow(default1);
      model.addRow(default2);

      model.addTableModelListener(this);

      this.add(new JScrollPane(table));
      table.setRowSorter(null);

   }

   public static TableModel1 getModel() {
      return model;
   }

   @Override
   public void tableChanged(TableModelEvent e) {
      int row = e.getFirstRow();
      int column = e.getColumn();

      // **** printf added below
      System.out.printf("[row: %d, column: %d]%n", row, column);

      model = (TableModel1) e.getSource();

      String columnName = model.getColumnName(column);

      // **** println added below
      System.out.println("columnName: " + columnName);

      Object data = model.getValueAt(row, column);

      if (model.getValueAt(row, column) == Boolean.TRUE) {
         System.out.println("Condition working");

         // *** AIOOBE called here
         model.removeRow(row);
      }
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            ExpenditurePanel panel = new ExpenditurePanel();
            JFrame frame = new JFrame("foo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel);
            frame.setLocationRelativeTo(null);
            frame.pack();
            frame.setVisible(true);
         }
      });
   }
}

// **** no idea how close this is to your code *****
class TableModel1 extends DefaultTableModel {
   @Override
   public Class<?> getColumnClass(int columnIndex) {
      if (getRowCount() == 0) {
         return super.getColumnClass(columnIndex);
      }
      Object value = getValueAt(0, columnIndex);
      if (value == null) {
         return super.getColumnClass(columnIndex);
      }

      return value.getClass();
   }
}

I get this output:

[row: 0, column: 5]
columnName: Remove
Condition working
[row: 0, column: -1]
columnName: 
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.Vector.elementAt(Unknown Source)
    ...... etc ......

So you see the model listener's `tableChanged(...)` method is called twice due to a recursion occurring from changing the listened to object inside of the listener, and the second time it's called, it has a column of -1 which causes your AIOOBE to be thrown.

Edit 2 A potential solution is to remove the listener before making the change to the model and then re-adding the listener after making the change:

public void tableChanged(TableModelEvent e) {
  int row = e.getFirstRow();
  int column = e.getColumn();
  System.out.printf("[row: %d, column: %d]%n", row, column);
  model = (TableModel1) e.getSource();
  String columnName = model.getColumnName(column);
  System.out.println("columnName: " + columnName);
  Object data = model.getValueAt(row, column);

  if (model.getValueAt(row, column) == Boolean.TRUE) {
     System.out.println("Condition working");

     model.removeTableModelListener(this);
     model.removeRow(row);
     model.addTableModelListener(this);
  }
}

Problem

I have been browsing numerous sites about this and tried some different things but im stumped. Would be grateful for some help. The condition is working that checks if a checkbox is selected (true) but soon as I do model.removeRow(row) it gives me this error. ``` public class ExpenditurePanel extends JPanel implements TableModelListener{ private static final long serialVersionUID = 1L; private static TableModel1 model; private JTable table; public ExpenditurePanel() { model = new TableModel1(); table = new JTable(model); table.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null)); table.setRowSelectionAllowed(false); table.setFillsViewportHeight(true); table.setCellSelectionEnabled(true); table.setColumnSelectionAllowed(false); model.addColumn("Name"); model.addColumn("Week"); model.addColumn("Fortnight"); model.addColumn("Month"); model.addColumn("Year"); model.addColumn("Remove"); Object[] default1 = {"Accomodation","","","","",false}; Object[] default2 = {"Food","","","","",false}; model.addRow(default1); model.addRow(default2); model.addTableModelListener(this); this.add(new JScrollPane(table)); table.setRowSorter(null); } public static TableModel1 getModel(){ return model; } @Override public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); model = (TableModel1) e.getSource(); String columnName = model.getColumnName(column); Object data = model.getValueAt(row, column); if(model.getValueAt(row,column) == Boolean.TRUE){ System.out.println("Condition working"); //this part keeps giving me error. model.removeRow(row); } } } ``` This is what it throws out: ``` Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1 at java.util.Vector.elementData(Unknown Source) at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableModel.getValueAt(Unknown Source) at studentBudget.ExpenditurePanel.tableChanged(ExpenditurePanel.java:53) at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source) at javax.swing.table.AbstractTableModel.fireTableRowsDeleted(Unknown Source) at javax.swing.table.DefaultTableModel.removeRow(Unknown Source) at studentBudget.ExpenditurePanel.tableChanged(ExpenditurePanel.java:59) at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source) at javax.swing.table.AbstractTableModel.fireTableCellUpdated(Unknown Source) at javax.swing.table.DefaultTableModel.setValueAt(Unknown Source) at javax.swing.JTable.setValueAt(Unknown Source) at javax.swing.JTable.editingStopped(Unknown Source) at javax.swing.AbstractCellEditor.fireEditingStopped(Unknown Source) at javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(Unknown Source) at javax.swing.DefaultCellEditor.stopCellEditing(Unknown Source) at javax.swing.DefaultCellEditor$EditorDelegate.actionPerformed(Unknown Source) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.JToggleButton$ToggleButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at javax.swing.plaf.basic.BasicTableUI$Handler.repostEvent(Unknown Source) at javax.swing.plaf.basic.BasicTableUI$Handler.mouseReleased(Unknown Source) at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$000(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) ```

Original source

Related problems