Почему мой JTable выбрасывает прерывистые исключения?

Я работаю над программой Swing, которая использует JTable отображать информацию для пользователя. В настоящее время в таблице более 700 записей, но я обнаружил очень странную ошибку, которая кажется воспроизводимой случайно. Иногда JTable вызовет IndexOutOfBoundsException с индексом: 0, размером: 0. Я скомпилировал и запустил мою программу несколько раз, не меняя НИЧЕГО, и это исключение возникло бы случайным образом, когда исключение не появлялось, программа ведет себя нормально.

Я не могу предоставить код для этой проблемы, потому что для его выполнения требуется более 10 файлов. Почему это может происходить с JTable? Я нахожу действительно странным, как программа может генерировать исключение во время одного запуска программы и не генерировать исключение при другом запуске той же программы без изменений кода... Существуют ли общеизвестные ошибки, которые вызывают такое поведение в программы?

Я не совсем уверен, какие части кода я должен включить, но вот некоторая дополнительная информация.

Я создал Custom TableModel называется PlayerTableModel который используется для визуализации JTableДанные хранятся в ArrayLists которые находятся в другом классе. Вот код для TableModel

public class PlayerTableModel extends AbstractTableModel {

    ArrayList<User> users = FileHandler.getAllPlayers();
    ArrayList<PlayerSummary.Player> summaries = FileHandler.getAllSummaries();

    @Override
    public int getColumnCount() {

        return 7;
    }

    @Override
    public int getRowCount() {

        return users.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {

        User user = users.get(rowIndex);

        switch (columnIndex) {
        case 0:
            if (user.getSteamId().equalsIgnoreCase(summaries.get(rowIndex).getSteamID())) {  // This is line 39
                return summaries.get(rowIndex).getPersonaName();
            } else {
                return null;
            }
        case 1:
            return user.getDateAdded();
        case 2:
            return user.getDateUpdated();
        case 3:
            return user.getNumberOfBans();
        case 4:
            return user.getNumberOfGameBans();
        case 5:
            return user.getDaysSinceLastBan();
        case 6:
            return user.getSteamId();
        }

        return null;
    }

    public String getColumnName(int columnIndex) {

        switch (columnIndex) {
        case 0:
            return "ID";
        case 1:
            return "Date added";
        case 2:
            return "Date updated";
        case 3:
            return "VAC bans";
        case 4:
            return "Game bans";
        case 5:
            return "Last ban (days)";
        case 6:
            return "64-Bit SteamID";
        }
        return null;

    }

    public boolean isCellEditable(int row, int column) {
        return false;
    }

}

При запуске программы, иногда я получаю это исключение, которое кажется какой-то проблемой потока?

Исключение в потоке "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(Неизвестный источник) в java.util.ArrayList.get(Неизвестный источник) в PlayerTableModel.getValueAt(PlayerTableModel.java:39) в javax.swing.JTable.getValueAt(неизвестный источник) в javax.swing.JTable.prepareRenderer(неизвестный источник) в javax.swing.plaf.synth.SynthTableUI.paintCell(неизвестный источник).swing.plaf.synth.SynthTableUI.paintCells(неизвестный источник) на javax.swing.plaf.synth.SynthTableUI.paint(неизвестный источник) на javax.swing.plaf.synth.SynthTableUI.update(неизвестный источник).JComponent.paintComponent(неизвестный источник) на javax.swing.JComponent.paint(неизвестный источник) на javax.swing.JComponent.paintChildren(неизвестный источник) на javax.swing.JComponent.paint(неизвестный источник) на javax.swing.Jport.paint (неизвестный источник) на javax.swing.JComponent.paintChildren(неизвестный источник) на javax.swing.JComponent.paint(неизвестный источник) на javax.swing.JComponent.paintChildren(Неизвестный источник) в javax.swing.JComponent.paint(Неизвестный источник) в javax.swing.JComponent.paintChildren(Неизвестный источник) в javax.swing.JComponent.paint(Неизвестный источник) в javax.swing.JComponent.paintChildren(Неизвестный Источник) в javax.swing.JComponent.paint(Неизвестный источник) в javax.swing.JComponent.paintToOffscreen(Неизвестный источник) в javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Неизвестный источник) в javax.swing.RepaintMagerpanager $ (Неизвестный источник) в javax.swing.RepaintManager.paint(Неизвестный источник) в javax.swing.JComponent._paintImmediately(Неизвестный источник) в javax.swing.JComponent.paintImmediately(Неизвестный источник) в javax.swing.RepaintManager$4.run(Неизвестный источник) в javax.swing.RepaintManager$4.run(Неизвестный источник) в java.security.AccessController.doPrivileged(собственный метод) в java.security.ProtectionDomain$1.doIntersectionPrivilege(Неизвестный источник) в javax.swing.RepaintDirtyg.pager Неизвестный источник) на javax.swing.RepaintManager.paintDirtyRegions(Неизвестный источник) в javax.swing.RepaintManager.prePaintDirtyRegions (Неизвестный источник) в javax.swing.RepaintManager.access$1300(Неизвестный источник) в javax.swing.RepaintManager$ProcessingRunnable.run(Неизвестный источник) в java.awt.event.InvocationEvent.dispatch(неизвестный источник) в java.awt.EventQueue.dispatchEventImpl(неизвестный источник) в java.awt.EventQueue.access$500(неизвестный источник) в java.awt.EventQueue$3.run(неизвестный источник) в java.awt. EventQueue $ 3.run (неизвестный источник) в java.security.AccessController.doPrivileged(собственный метод) в java.security.ProtectionDomain$1.doIntersectionPrivilege(неизвестный источник) в java.awt.EventQueue.dispatchEvent(неизвестный источник) в java.awt.EventDispatchThread.pumpOneEventForFilters(Неизвестный источник) в java.awt.EventDispatchThread.pumpEventsForFilter(Неизвестный источник) в java.awt.EventDispatchThread.pumpEventsForHierarchy(Неизвестный источник) в java.awt.EventDisp.pumpEvents(Неизвестный источник) на java.awt.Ev entDispatchThread.run (неизвестный источник)

Данные записываются и читаются из файла, используя FileHandler учебный класс:

public class FileHandler implements Serializable {

    private static ArrayList<User> tracked = new ArrayList<User>();

    private static ArrayList<PlayerSummary.Player> trackedSummaries = new ArrayList<PlayerSummary.Player>();

    private static ArrayList<PlayerSummary.Player> trackedSummariesUnsorted = new ArrayList<PlayerSummary.Player>();

    private static ArrayList<String[]> games = new ArrayList<String[]>();

    private static String savedString = "";

    private static String APIKEY = "";

    public static void writeToFile(String fileName, Object objToWrite) {

        try {
            // Write object to file.
            FileOutputStream fOS = new FileOutputStream(fileName);
            ObjectOutputStream oOS = new ObjectOutputStream(fOS);
            oOS.writeObject(objToWrite);
            oOS.close();

            // Write string to text file so that it can be displayed.
            if (fileName.equalsIgnoreCase("apikey.txt")) {
                File file = new File(fileName);
                PrintWriter pw = new PrintWriter(file);
                pw.print(objToWrite);
                pw.close();
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void readFromFile(String fileName, String objType) {
        FileInputStream fIS;
        try {

            fIS = new FileInputStream(fileName);
            ObjectInputStream oIS = new ObjectInputStream(fIS);

            if (objType.equalsIgnoreCase("ArrayList<User>")) {
                tracked = (ArrayList<User>) oIS.readObject();
            } else if (objType.equalsIgnoreCase("ArrayList<PlayerSummary.Player>")) {
                if (fileName.equalsIgnoreCase("summaries.tmp")) {
                    trackedSummaries = (ArrayList<PlayerSummary.Player>) oIS.readObject();
                }
                if (fileName.equalsIgnoreCase("s_unsorted.tmp")) {
                    trackedSummariesUnsorted = (ArrayList<PlayerSummary.Player>) oIS.readObject();
                }
            } else if (objType.equalsIgnoreCase("ArrayList<String[]>")) {
                games = (ArrayList<String[]>) oIS.readObject();
            } else if (objType.equalsIgnoreCase("apikey")) {
                APIKEY = (String) oIS.readObject();
            }else {
                System.out.println("Object type " + objType + " needs to be implemented!");
            }

            oIS.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static ArrayList<User> getAllPlayers() {
        return tracked;
    }

    public static ArrayList<PlayerSummary.Player> getAllSummaries() {
        return trackedSummaries;
    }

    public static ArrayList<PlayerSummary.Player> getAllSummariesUnsorted() {
        return trackedSummariesUnsorted;
    }

    public static ArrayList<String[]> getGames() {
        return games;
    }

    public static String getAPIKey() {

        try {

            BufferedReader br = new BufferedReader(new FileReader("apikey.txt"));
            APIKEY = br.readLine();

        } catch (FileNotFoundException e) {
            JOptionPane.showMessageDialog(BanTracker.getFrames()[0], "File not found! Did you save your API key?");
            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }
        return APIKEY;
    }

    public static void updateArrayList(ArrayList<User> a) {
        tracked = a;
    }

}

1 ответ

Решение

Ваш класс FileHandler не загружает файлы в потоке отправки событий, поэтому вы вызываете состояние гонки между этим потоком и потоком отправки событий.

В любом случае вы не должны получать статический доступ к своим файлам; вставьте Users и Summaries в табличную модель при создании еще до того, как JTable будет визуализирован. Другими словами, просто создайте конструктор:

public class PlayerTableModel extends AbstractTableModel {
  private final List<User> users;
  private final List<PlayerSummary.Player> summaries;

  public PlayerTableModel(List<User> users, List<PlayerSummary.Player> summaries) {
    this.users = new ArrayList<User>(users);
    this.summaries = new ArrayList<PlayerSummary.Player>(summaries);
  }
}

Затем, прежде чем даже создавать JTable, убедитесь, что файлы загружены:

TableModel model = new PlayerTableModel(FileHandler.getAllPlayers(),
             FileHandler.getAllSummaries());
JTable table = new JTable(model);

Это должно гарантировать, что вся загрузка происходит, когда она должна (когда программа запускается), и ошибка должна исчезнуть.

Кроме того, попробуйте изменить TableModel, чтобы сделать это:

@Override
public int getRowCount() {
    return Math.min(users.size(), summaries.size());
}

Я не уверен, что это решит вашу проблему, но я думаю, что вы будете намного, намного счастливее, если вы сделаете это:

public class CompletePlayer {
  public final User user;
  public final PlayerSummer.Player summary;
}

Затем используйте только один ArrayList вместо двух. Прочитайте пост Эрнеста Фридмана о параллельных массивах здесь

Другие вопросы по тегам