Почему мой 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 вместо двух. Прочитайте пост Эрнеста Фридмана о параллельных массивах здесь