JList/DefaultListModel持续Insert和Remove数据产生ArrayIndexOutOfBoundsException的问题

本文介绍如何使用 Java Swing 的 JList 控件实现数据的动态更新和边界控制,避免因线程操作导致的 ArrayIndexOutOfBoundsException 异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.youkuaiyun.com/swingline/article/details/5496008

有这样一个需求:往一个JList中持续Insert数据,当JList中的数据量大于某个值时(比如大于5行),就开始删除数据,使得JList中的数据量一直为固定值(如5行),下面是测试代码:

[java]  view plain copy
  1. import javax.swing.DefaultListModel;  
  2. import javax.swing.JFrame;  
  3. import javax.swing.JList;  
  4. import javax.swing.SwingUtilities;  
  5. public class ListBoundTestMain extends JFrame {  
  6.     JList m_list = null;  
  7.     DefaultListModel m_model = null;  
  8.       
  9.     public static void main(String[] args) {  
  10.         new ListBoundTestMain().initView();  
  11.     }  
  12.       
  13.     public void initView() {  
  14.         m_model = new DefaultListModel();  
  15.         m_list = new JList(m_model);  
  16.         getContentPane().add(m_list);  
  17.         m_model.insertElementAt("Test1"0);  
  18.         m_model.insertElementAt("Test2"0);  
  19.         m_model.insertElementAt("Test3"0);  
  20.         m_model.insertElementAt("Test4"0);  
  21.         m_model.insertElementAt("Test5"0);  
  22.           
  23.         setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  
  24.         setSize(600600);  
  25.           
  26.         new Thread(){  
  27.             private int i = 0;  
  28.             public void run() {  
  29.                 while(true) {  
  30.                     i++;  
  31.                     m_model.insertElementAt("Loop"+i, 0);  
  32.                     System.out.println("Loop"+i);  
  33.                     System.out.println("Before size="+m_model.getSize());  
  34.                     m_model.remove(m_model.getSize()-1);  
  35.                     try {  
  36.                         Thread.sleep(50);  
  37.                     }catch (Exception e) {  
  38.                         // TODO: handle exception  
  39.                     }  
  40.                     System.out.println("After size="+m_model.getSize());  
  41.                 }  
  42.             }  
  43.         }.start();  
  44.           
  45.         setVisible(true);  
  46.     }  
  47. }  

 

上面的测试代码会每隔一段时间就报一个异常:

[java]  view plain copy
  1. Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 5 >= 5  
  2.     at java.util.Vector.elementAt(Unknown Source)  
  3.     at javax.swing.DefaultListModel.getElementAt(Unknown Source)  
  4.     at javax.swing.plaf.basic.BasicListUI.updateLayoutState(Unknown Source)  
  5.     at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(Unknown Source)  
  6.     at javax.swing.plaf.basic.BasicListUI.paintImpl(Unknown Source)  
  7.     at javax.swing.plaf.basic.BasicListUI.paint(Unknown Source)  
  8.     at javax.swing.plaf.ComponentUI.update(Unknown Source)  
  9.     at javax.swing.JComponent.paintComponent(Unknown Source)  
  10.     at javax.swing.JComponent.paint(Unknown Source)  
  11.     at javax.swing.JComponent.paintToOffscreen(Unknown Source)  
  12.     at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)  
  13.     at javax.swing.RepaintManager.paint(Unknown Source)  
  14.     at javax.swing.JComponent._paintImmediately(Unknown Source)  
  15.     at javax.swing.JComponent.paintImmediately(Unknown Source)  
  16.     at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)  
  17.     at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)  
  18.     at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)  
  19.     at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)  
  20.     at java.awt.event.InvocationEvent.dispatch(Unknown Source)  
  21.     at java.awt.EventQueue.dispatchEvent(Unknown Source)  
  22.     at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)  
  23.     at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)  
  24.     at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)  
  25.     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)  
  26.     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)  
  27.     at java.awt.EventDispatchThread.run(Unknown Source)  

 

 

经过搜索查找,终于找到问题所在:原来并不是DefaultListModel边界的溢出,而是上面插入/删除数据是在一个新的线程里进行,而界面绘制要求在Event Dispatch Thread中进行,所以当应用程序线程需要更新GUI时,需要把代码包在SwingUtilities.invokeLater()中来处理,使得它们重新回到Event Dispatch Thread中。

 

看看invokeLater的描述:

public static void invokeLater(Runnable doRun)
Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed. This method should be used when an application thread needs to update the GUI. In the following example the invokeLater call queues the Runnable object doHelloWorld on the event dispatching thread and then prints a message. 
 Runnable doHelloWorld = new Runnable() {
     public void run() {
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };
 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

 

 

 

把上面测试例子稍微改一下:

[java]  view plain copy
  1. public class ListBoundTestMain extends JFrame {  
  2.     JList m_list = null;  
  3.     DefaultListModel m_model = null;  
  4.       
  5.     public static void main(String[] args) {  
  6.         new ListBoundTestMain().initView();  
  7.     }  
  8.       
  9.     public void initView() {  
  10.         m_model = new DefaultListModel();  
  11.         m_list = new JList(m_model);  
  12.         getContentPane().add(m_list);  
  13.         m_model.insertElementAt("Test1"0);  
  14.         m_model.insertElementAt("Test2"0);  
  15.         m_model.insertElementAt("Test3"0);  
  16.         m_model.insertElementAt("Test4"0);  
  17.         m_model.insertElementAt("Test5"0);  
  18.           
  19.         setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  
  20.         setSize(600600);  
  21.           
  22.         new Thread(){  
  23.             private int i = 0;  
  24.             public void run() {  
  25.                 while(true) {  
  26.                     try {  
  27.                         Thread.sleep(500);  
  28.                     }catch (Exception e) {  
  29.                         // TODO: handle exception  
  30.                     }  
  31.                     SwingUtilities.invokeLater(new Runnable() {  
  32.                         public void run() {  
  33.                             i++;  
  34.                             m_model.insertElementAt("Loop"+i, 0);  
  35.                             System.out.println("Loop"+i);  
  36.                             System.out.println("Before size="+m_model.getSize());  
  37.                             m_model.remove(m_model.getSize()-1);  
  38.                               
  39.                             System.out.println("After size="+m_model.getSize());  
  40.                         }  
  41.                     });  
  42.                       
  43.                 }  
  44.             }  
  45.         }.start();  
  46.           
  47.         setVisible(true);  
  48.     }  
  49. }  

 

 

 

 

另外,ArrayIndexOutOfBoundsException也可能是由于数组边界溢出,如果是数组边界溢出,提示应该这个样子的:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 3

 

 

 

 

 

参考:http://www.mofeel.net/858-comp-lang-java-gui/5523.aspx

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值