# java.lang.IndexOutOfBoundsException:



## dior (23. Mrz 2016)

Hi,

ich fülle eine TableView mit Daten aus einer DB.
Das ganze läuft auch gut solange ich keine Daten abrufen die mehr Spalten hat als die Vorherige.
Beispiel:
1. Abfrage hat 30 Spalten. Das Ergebnis wird angezeigt.
2. Abfrage hat 16 Zeilen. Wenn ich diese starte kommt:


> Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException: Index: 16, Size: 16
> at java.util.ArrayList.rangeCheck(ArrayList.java:653)
> at java.util.ArrayList.get(ArrayList.java:429)



Wenn ich zuerst die mit 16 Zeilen Ausführe und dann die mit 30 kommt kein Fehler.

Hier der Code der Methode in der der Fehler passiert:

```
public void buildData() {
      //  tableview1.getItems().clear();
     
        data = FXCollections.observableArrayList();
       System.out.println("index: " + data.indexOf(c));
    //   System.out.println("index: " + row.indexOf(row));
        try {
            c = DB._DB_Connection.getConnection();
            System.out.println("real SQL: " + SQL);
            ResultSet rs = c.createStatement().executeQuery(SQL);
            TableColumn col = new TableColumn();
            // data.clear();
           
           
            /* TABLE COLUMN ADDED DYNAMICALLY */
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
               
                //We are using non property style for making dynamic table
                final int j = i;
                col = new TableColumn(rs.getMetaData().getColumnName(i + 1));
                col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
                    public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
                        return new SimpleStringProperty(param.getValue().get(j).toString());
                    }
                });

                int rowNr = i + 1;
                System.out.println("Column [" + rowNr + "] " + rs.getMetaData().getColumnName(rowNr));
                tableview1.getColumns().addAll(col);
            }
            /* Data added to ObservableList */
            //int zeile = 1;  // Wert für ExcelExport
            while (rs.next()) {

                row = FXCollections.observableArrayList();
                for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                    Object o = rs.getObject(i);
                    row.add(o == null ? "" : o.toString()); // wenn ein NULL Value gefunden wird, wird dieser durch "" ersetzt
                }
                data.addAll(row);
            }
                      
            tableview1.setItems(data);
            ausgabe1.setText("" + data.size());
            System.out.println("Anzahl der Zeilen: " + data.size());
            System.out.println("index: " + data.indexOf(data));
            System.out.println("indexTableView: " + data.indexOf(tableview1));
            System.out.println("index: " + row.indexOf(row));

            // Rechtsklick in TableView initialisieren!
            RechtsKlickMenue();

            rs.close();
            c.close();

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Error on Building Data");
        }

    }
```


----------



## Joose (23. Mrz 2016)

Der StackTrace sagt dir genau in welcher Zeile dieser Fehler auftritt, leider hast du nicht den vollständigen StackTrace gepostet und auch nicht gezeigt bei welcher Zeile der Fehler auftritt.
Ansonsten ist die Fehlermeldung eindeutig: Du greifst auf einen Index zu den es nicht gibt. Warum wieso weshalb können wir nur raten da uns die genaue Fehlerquelle nicht gesagt wurde. Aber mittels Debugger sollte es dir auch selber möglich sein herauszufinden warum wieso weshalb


----------



## dior (23. Mrz 2016)

Hier die komplette Exception:

die Zeilen 144 - 146 sind diese hier (= FXMLDocumentController.java):

```
col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
                    public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
                        return new SimpleStringProperty(param.getValue().get(j).toString());
```


```
Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException: Index: 16, Size: 16
    at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    at java.util.ArrayList.get(ArrayList.java:429)
    at com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89)
    at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:146)
    at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:144)
    at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578)
    at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:563)
    at javafx.scene.control.TableCell.updateItem(TableCell.java:644)
    at javafx.scene.control.TableCell.indexChanged(TableCell.java:468)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.requestCellUpdate(TableRowSkinBase.java:659)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.lambda$init$497(TableRowSkinBase.java:159)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:105)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
    at javafx.scene.control.Cell.setItem(Cell.java:403)
    at javafx.scene.control.Cell.updateItem(Cell.java:670)
    at javafx.scene.control.TableRow.updateItem(TableRow.java:259)
    at javafx.scene.control.TableRow.indexChanged(TableRow.java:225)
    at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1957)
    at com.sun.javafx.scene.control.skin.VirtualFlow.addLeadingCells(VirtualFlow.java:1246)
    at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1194)
    at com.sun.javafx.scene.control.skin.VirtualFlow.setCellCount(VirtualFlow.java:231)
    at com.sun.javafx.scene.control.skin.TableViewSkinBase.updateRowCount(TableViewSkinBase.java:567)
    at com.sun.javafx.scene.control.skin.VirtualContainerBase.checkState(VirtualContainerBase.java:113)
    at com.sun.javafx.scene.control.skin.VirtualContainerBase.layoutChildren(VirtualContainerBase.java:108)
    at com.sun.javafx.scene.control.skin.TableViewSkinBase.layoutChildren(TableViewSkinBase.java:696)
    at javafx.scene.control.Control.layoutChildren(Control.java:576)
    at javafx.scene.Parent.layout(Parent.java:1087)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Parent.layout(Parent.java:1093)
    at javafx.scene.Scene.doLayoutPass(Scene.java:552)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
```


----------



## dior (30. Mrz 2016)

Ich komme hier leider nicht weiter. Kann mir hier noch jemand einen Tipp geben was ich machen könnte?


----------



## Joose (30. Mrz 2016)

```
return new SimpleStringProperty(param.getValue().get(j).toString());
```

Ich gehe davon aus du du hier mit "get(j)" auf einen nicht vorhanden Index zugreifen willst.
Überlege und versuche herauszufinden warum dort mittels falschen Index zugegriffen wird, vielleicht gibt es wo einen Denkfehler und das Problem lässt sich so lösen. Leider lässt sich nicht erkennen woher "j" kommt, wo wird der Wert dieser Variable gesetzt usw.


----------



## dior (30. Mrz 2016)

Ich weise j=i aus der For-Schleife zu:

```
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
               
                 //We are using non property style for making dynamic table
                 final int j = i;
```


----------



## Joose (30. Mrz 2016)

Stimmt übersehen 
Aber ja ändert nichts an der Tatsache das du bei diesem "CellValueFactory" Dings mit einen falschen Index zugreifst. Warum kann ich dir nicht genau sagen da ich damit noch nicht gearbeitet habe.
Wirf den Debugger an und kontrolliere um was für ein Objekt es sich bei "param" handelt. Was bekommst du zurück mit getValue()? Wieviele Elemente enthält dieses Objekt?


----------



## dior (30. Mrz 2016)

param.getValue() beinhaltet die einzelnen Zeilen der DB Abfrage.
frage wie ich die Werte da wieder löschen kann wenn ich eine neue Abfrage mache.


----------



## dzim (30. Mrz 2016)

Ok, ich verstehe deinen Code weitgehend. Du willst dynamisch Tabellen aus einer DB und deren Spalten Anzeigen. Korrekt?

Ich vermute, dass das Problem einfach dadurch entsteht, dass du zuerst die Spalten (TableColumn) anlegst und bereits mit noch nicht vorhandenen Daten verknüpfst (obwohl ich dachte, dass das erst relevant ist, wenn man tatsächlich Daten anzeigen muss). Die JavaFX-Tabelle wird ja bereits initialisiert/geupdatet, wenn du "tableview1.getColumns().addAll(col);" ausführst. Aber ich bin mir nicht zu 100% sicher, dass ich es richtig verstanden habe.

Des weiteren verstehe ich aber noch nicht deinen Code für die eigentlichen Daten. Du liest die Row in eine Liste ein und fügst diese dann den Daten mit #addAll hinzu. Ist deine Tabelle so etwas wie "TableView<List<String>>"?

Wann passiert das eigentlich? Erst beim zweiten Durchlauf der SQL Query? Wenn ja, dann müsstest du vielleicht vorher die Daten (und evtl. auch die TableColumns) clearen.


----------



## dior (30. Mrz 2016)

Die Daten sind in einer ObservableList

public static ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
  public static ObservableList<String> row = FXCollections.observableArrayList();


----------



## dior (30. Mrz 2016)

Noch etwas ist mir aufgefallen....
Wenn ich 
	
	
	
	





```
tableview1.setItems(data);
```
 auskommtentiere dann kommt keine IndexOutOfBounndsException. Natürlich werden auch keine Daten in der TableView angezeigt.

Ich müsste also "nur" die TableView vorher wieder leeren, aber ich bekomme das nicht hin, leider....


----------



## dzim (30. Mrz 2016)

"tableview1.getItems().clear()" - das ist am Ende auch nur eine List-Implementierung.
Und eventuell auch noch "tableview1.getColumns().clear()" vorher, damit alle Spalten wirklich neu gemacht werden (wenn notwendig).

Im Prinzip dort, wo der Teil am Anfang deiner #buildData()-Methode auskommentiert steht...

Noch etwas fällt mir auf: Ich vermute, dass deine Oberfläche auch noch kurz "einfriert", oder? Denn so wie es aussieht, machst du die DB-Operation auf dem UI-Thread (stelle dir gerade vor, wie ich einen Seufzer von mir gebe und mit dem Kopf schüttel ).
Wenn dein Problem behoben ist, solltest du das in einen eigenen Thread auslagern (z.B. in einem JavaFX-Task).


----------



## dior (31. Mrz 2016)

Danke für die Hilfe!

Aber ich komme noch immer nicht ganz zurecht... ich habe jetzt

```
public void buildData() {
      tableview1.getItems().clear();
      tableview1.getColumns().clear();
      
       System.out.println("index: " + data.indexOf(c));
        try {
            c = DB._DB_Connection.getConnection();
            System.out.println("real SQL: " + SQL);
            ResultSet rs = c.createStatement().executeQuery(SQL);
            TableColumn col = new TableColumn();
.
.
.
```

und bekomme beim 2. mal Ausführen einer Abfrage nichtmehr die IndexOutOfBoundsException sondern:


> Exception in thread "JavaFX Application Thread" java.lang.UnsupportedOperationException
> at java.util.AbstractList.remove(AbstractList.java:161)
> at java.util.AbstractList$Itr.remove(AbstractList.java:374)
> at java.util.AbstractList.removeRange(AbstractList.java:571)
> ...


----------



## dzim (31. Mrz 2016)

> at FX.FXMLDocumentController.buildData(FXMLDocumentController.java:123)


Was ist Zeile 123 in deinem Code?


----------



## dior (31. Mrz 2016)

```
(122) public void buildData() {
(123)      tableview1.getItems().clear();
(124)      tableview1.getColumns().clear();
```


----------



## dzim (31. Mrz 2016)

Ok, dann fällt mir gerade nichts mehr dazu ein. Wie wird #buildData() aufgerufen? Die erste Runde im initialize und die Zweite manuell?


----------



## dior (31. Mrz 2016)

Ich habe eine TreeView mit ein paar Einträgen.
Beide male rufe ich die Abfrage "manuell" auf.


```
TreeItem<String> uwsw = new TreeItem<>("USW");
TreeItem<String> gasHA = new TreeItem<>("GHA");
```


```
/* *************************************************************************************************
        ** Action Event wenn Auswahl in TreeView getroffen wurde
        ************************************************************************************************** */
        treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {

            @Override
            public void changed(ObservableValue observable, Object oldVal, Object newVal) {
                System.out.println(oldVal + " neuer: " + newVal);

                switch (newVal.toString()) {
case "TreeItem [ value: USW ]":
                        sqlDatei = "USW.txt";
                        xlsxSheetName = sqlDatei.substring(0, sqlDatei.lastIndexOf('.'));
                        // xlsxDateiName = xlsxDateiName + sqlDatei.substring(0, sqlDatei.lastIndexOf('.')) + ".xlsx";
                        pIVisible();
                        AuswahlClicked();
                        buildData();
                        Platform.runLater(() -> new TableFilter(tableview1));
                        ;
                        break;
case "TreeItem [ value: GHA ]":
                        sqlDatei = "gha.txt";
                        AuswahlClicked();
                        buildData();
                        Platform.runLater(() -> new TableFilter(tableview1));
                       
                        break;
.
.
.
```


----------



## dior (31. Mrz 2016)

Jetzt hab ich es... nach dem kopieren vom letzten code:

Platform.runLater(() -> new TableFilter(tableview1));

muss aus der TreeView weg, dann klappt es 

DANKE


----------



## dior (1. Apr 2016)

So ich hab jetzt noch das Problem mit der DB-Operation und der GUI in einen anderen Thread geschrieben.
Ich will ja schließlich auch eine Ladeanzeige haben, aktuell friert die GUI halt ein...
http://www.java-forum.org/thema/ui-thread-und-db-thread-trennen-um-z-b-ladebalken-anzuzeigen.172411/


----------

