为什么我的JTable会抛出间歇性异常?

时间:2015-07-20 02:39:03

标签: java swing exception jtable

我正在使用一个使用JTable向用户显示信息的Swing程序。该表目前有700多个条目,但我发现了一个非常奇怪的错误,似乎可以随机重现。有时JTable将导致IndexOutOfBoundsException索引:0,大小:0。我编译并运行我的程序多次而不更改任何东西,当异常没有到来时,这个异常会随机出现该程序运行正常。

我无法为此问题提供代码,因为它需要超过10个文件才能运行。为什么JTable会发生这种情况?我发现一个程序在程序的一次运行期间如何抛出异常并且不会在同一程序的另一次运行中抛出异常并且没有代码更改,这真的很奇怪......是否存在导致此类行为的任何常见错误程序

我不确定我应该包含哪些代码部分,但这里有一些额外的信息。

我创建了一个名为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(未知来源)at   java.util.ArrayList.get(未知来源)at   PlayerTableModel.getValueAt(PlayerTableModel.java:39)at   javax.swing.JTable.getValueAt(未知来源)at   javax.swing.JTable.prepareRenderer(未知来源)at   javax.swing.plaf.synth.SynthTableUI.paintCell(未知来源)at   javax.swing.plaf.synth.SynthTableUI.paintCells(未知来源)at   javax.swing.plaf.synth.SynthTableUI.paint(未知来源)at   javax.swing.plaf.synth.SynthTableUI.update(未知来源)at   javax.swing.JComponent.paintComponent(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JComponent.paintChildren(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JViewport.paint(未知来源)at   javax.swing.JComponent.paintChildren(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JComponent.paintChildren(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JComponent.paintChildren(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JComponent.paintChildren(未知来源)at   javax.swing.JComponent.paint(未知来源)at   javax.swing.JComponent.paintToOffscreen(未知来源)at   javax.swing.RepaintManager中的$ PaintManager.paintDoubleBuffered(未知   来自)javax.swing.RepaintManager $ PaintManager.paint(未知   来源)在javax.swing.RepaintManager.paint(未知来源)at   javax.swing.JComponent._paintImmediately(未知来源)at   javax.swing.JComponent.paintImmediately(未知来源)at   javax.swing.RepaintManager $ 4.run(未知来源)at   javax.swing.RepaintManager $ 4.run(未知来源)at   java.security.AccessController.doPrivileged(Native Method)at   java.security.ProtectionDomain $ 1.doIntersectionPrivilege(未知   来源)在javax.swing.RepaintManager.paintDirtyRegions(未知   来源)在javax.swing.RepaintManager.paintDirtyRegions(未知   来自)javax.swing.RepaintManager.prePaintDirtyRegions(未知   来源)在javax.swing.RepaintManager.access $ 1300(未知来源)at   javax.swing.RepaintManager $ ProcessingRunnable.run(未知来源)at   java.awt.event.InvocationEvent.dispatch(未知来源)at   java.awt.EventQueue.dispatchEventImpl(未知来源)at   java.awt.EventQueue.access $ 500(未知来源)at   java.awt.EventQueue $ 3.run(未知来源)at   java.awt.EventQueue $ 3.run(未知来源)at   java.security.AccessController.doPrivileged(Native Method)at   java.security.ProtectionDomain $ 1.doIntersectionPrivilege(未知   来自)java.awt.EventQueue.dispatchEvent(未知来源)at   java.awt.EventDispatchThread.pumpOneEventForFilters(未知来源)     at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)     在java.awt.EventDispatchThread.pumpEventsForHierarchy(未知   来自java.awt.EventDispatchThread.pumpEvents(未知来源)     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)at   java.awt.EventDispatchThread.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 个答案:

答案 0 :(得分:1)

您的FileHandler类未加载Event Dispatch Thread上的文件,因此您在该线程与事件调度线程之间导致争用条件。

您无论如何都不应该静态访问您的文件;在创建JTable之前,将Users和Summaries注入到表模型中。换句话说,只需创建一个构造函数:

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而不是两个。阅读Ernest Friedman的帖子here about parallel arrays