为什么我的JTable抛出间歇性异常? [英] Why does my JTable throw intermittent exceptions?

查看:99
本文介绍了为什么我的JTable抛出间歇性异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用JTable向用户显示信息的Swing程序.该表目前有700多个条目,但是我发现了一个很奇怪的错误,似乎可以随机再现.有时JTable会导致索引为0,大小为0的IndexOutOfBoundsException.我已经多次编译并运行了程序,而没有更改任何内容,并且此异常将随机出现,当异常不出现时,程序表现正常.

I am working on a Swing program that uses a JTable to display information to the user. The table currently has over 700 entries but I have found a very weird bug that seems to be reproducible randomly. Sometimes the JTable will cause an IndexOutOfBoundsException with Index: 0, Size: 0. I have compiled and ran my program multiple times without changing ANYTHING and this exception would come up randomly, when the exception does not come up, the program behaves normally.

我无法提供此问题的代码,因为它需要10个以上的文件才能运行.为什么JTable会发生这种情况?我发现程序在一次运行期间如何抛出异常而又在没有代码更改的情况下在同一程序的另一次运行中引发异常真的很奇怪……是否存在引起这种行为的常见错误?程序?

I am unable to provide code for this problem because it requires over 10 files in order to run. Why might this be happening with JTable? I find it really weird how a program can throw an exception during one run of the program and not throw an exception at another run of the same program with no code changes... Are there any commonly known errors that cause this kind of behavior in programs?

我不确定我应该包括代码的哪些部分,但这是一些其他信息.

I am not really sure which parts of the code I should include but here is some additional information.

我创建了一个名为PlayerTableModel的自定义TableModel,用于渲染JTable.数据存储在另一个类的ArrayLists中.这是TableModel

I have created a Custom TableModel called PlayerTableModel which is used to render the JTable, The data is stored in ArrayLists that are in another class. Here is the code for the 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;
    }

}

在运行程序时,有时会出现此异常,这似乎是某种线程问题?

When running the program, sometimes I get this exception which seems to be some sort of thread issue?

线程"AWT-EventQueue-0"中的异常 java.lang.IndexOutOfBoundsException:索引:0,大小:0 at java.util.ArrayList.rangeCheck(未知源),位于 java.util.ArrayList.get(未知源),位于 PlayerTableModel.getValueAt(PlayerTableModel.java:39)位于 javax.swing.JTable.getValueAt(Unknown Source)位于 javax.swing.JTable.prepareRenderer(未知源),位于 javax.swing.plaf.synth.SynthTableUI.paintCell(未知源),位于 javax.swing.plaf.synth.SynthTableUI.paintCells(未知源)位于 javax.swing.plaf.synth.SynthTableUI.paint(未知源)在 javax.swing.plaf.synth.SynthTableUI.update(未知源) javax.swing.JComponent.paintComponent(未知源),位于 javax.swing.JComponent.paint(未知源) javax.swing.JComponent.paintChildren(未知来源),位于 javax.swing.JComponent.paint(未知源) javax.swing.JViewport.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.RepaintManager $ PaintManager.paint(未知 源)位于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.RepaintManager.paintDirtyRegions(未知 源代码)在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.EventDispatchThread.pumpEvents(未知源) 在java.awt.EventDispatchThread.pumpEvents(未知来源)处 java.awt.EventDispatchThread.run(未知来源)

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(Unknown Source) at java.util.ArrayList.get(Unknown Source) at PlayerTableModel.getValueAt(PlayerTableModel.java:39) at javax.swing.JTable.getValueAt(Unknown Source) at javax.swing.JTable.prepareRenderer(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paintCell(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paintCells(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.paint(Unknown Source) at javax.swing.plaf.synth.SynthTableUI.update(Unknown Source) at javax.swing.JComponent.paintComponent(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JViewport.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintChildren(Unknown Source) at javax.swing.JComponent.paint(Unknown Source) at javax.swing.JComponent.paintToOffscreen(Unknown Source) at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source) at javax.swing.RepaintManager$PaintManager.paint(Unknown Source) at javax.swing.RepaintManager.paint(Unknown Source) at javax.swing.JComponent._paintImmediately(Unknown Source) at javax.swing.JComponent.paintImmediately(Unknown Source) at javax.swing.RepaintManager$4.run(Unknown Source) at javax.swing.RepaintManager$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source) at javax.swing.RepaintManager.access$1300(Unknown Source) at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source) at java.awt.event.InvocationEvent.dispatch(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$500(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.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)

使用FileHandler类从文件中写入和读取数据:

The data is written and read from file, using the FileHandler class:

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;
    }

}

推荐答案

您的FileHandler类未加载

Your FileHandler class is not loading the files on the Event Dispatch Thread, so you're causing a race condition between that thread and the Event Dispatch Thread.

无论如何,您都不应静态访问文件;在创建JTable之前,在创建时将用户"和摘要"注入到表模型中.换句话说,只需创建一个构造函数:

You should not be accessing your files statically anyway; inject the Users and the Summaries into the table model at creation, before the JTable is even rendered. In other words, just create a constructor:

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之前,请确保已加载文件:

Then, before even constructing the JTable, ensure that the files are loaded:

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

这应该确保所有加载均在应有的时候发生(程序启动时),并且错误应该消失.

This should ensure that all the loading happens when it's supposed to (when the program starts), and the error should disappear.

此外,尝试修改TableModel来做到这一点:

Also, try modifying your TableModel to do this:

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

我不确定是否能解决您的问题,但我认为如果这样做,您会更加快乐:

I'm not sure if it will fix your problem, but I think you will be much, much happier if you do this:

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

然后,仅使用一个ArrayList而不是两个.阅读Ernest Friedman的帖子此处有关并行数组

Then, only use one ArrayList instead of two. Read Ernest Friedman's post here about parallel arrays

这篇关于为什么我的JTable抛出间歇性异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆