动态更新JComboBox时如何避免IndexOutOfBoundsexception

我使用SWING API编写了一个GUI。

我得到了一组表单,每个表单都帮助用户创建一个预定义类型的对象。 完成后,用户通过单击JButton确认创建。

我得到了一个遵循单例模式的类( DataManager )。 此外,该课程遵循观察者和工厂模式。 DataManager是一个可观察对象。 观察到的数据采用以下格式:

public static List targets = new ArrayList(); 

DataManager类包含一组方法来创建对象的预定义类型。
例:

 public static final void createTarget(String id, double x, double y, double z){ targets.add(new Target(id,x,y,z)); notifyTargetObservers(); } 

其中一种forms是观察者对象,它观察DataManager以获取其列表中保存的任何数据的更新(例如列表目标…)。

IObserve

 public interface IObserve { public void updateTargets(); public void updateSources(); public void updateFluids(); } 

观察者实现IObserver中引入的方法。
例:

 @Override public void updateTargets(){ cbAnalysisTargets.addItem(DataManager.targets.get(DataManager.targets.size()-1)); } 

cbAnalysisTargets是一个JComboBox ,需要在将新对象引入环境时动态更新。
IObservable

 public abstract class IObservable { private static Set targetObservers = new HashSet(); private static Set sourceObservers = new HashSet(); private static Set fluidObservers = new HashSet(); public final void addTargetObserver(IObserve o){ targetObservers.add(o); } public final void addSourceObserver(IObserve o){ sourceObservers.add(o); } public final void addFluidObserver(IObserve o){ fluidObservers.add(o); } public static final void notifyTargetObservers(){ for(IObserve observer : targetObservers){ observer.updateTargets(); } } public static final void notifySourceObservers(){ for(IObserve observer : sourceObservers){ observer.updateSources(); } } public static final void notifyFluidObservers(){ for(IObserve observer : fluidObservers){ observer.updateFluids(); } } } 

该问题存在于IndexOutOfBounds Exception中。 在以下情况中会出现exception:
1.用户打开第一个表单并成功启动创建2个相同类型的预定义对象。
2.用户打开第二个表格; 填写表格并在确认后(点击按钮)收到下面列出的例外情况。

理想情况下,我希望得到协助解决以下问题并解决下面提到的例外情况。

例外:

线程“AWT-EventQueue-0”中的exceptionjava.lang.IndexOutOfBoundsException:索引:1,大小:1,位于fprof的java.util.ArrayList.get(未知源)的java.util.ArrayList.rangeCheck(未知源)。 application.data.frame.manager.content.AnalysisCreatorPanel.updateSources(AnalysisCreatorPanel.java:99)at fprof.application.utility.IObservable.notifySourceObservers(IObservable.java:32)at fprof.application.data.manager.IDataManager.createSource( IDataManager.java:29)at fprof.application.data.frame.manager.content.SourceCreatorPanel $ 1.actionPerformed(SourceCreatorPanel.java:127)at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)at javax.swing.AbstractButton $ Handler位于java.awt的javax.swing.plaf.basic.BasicButtonListener.mouseReleased(未知来源)的javax.swing.DefaultButtonModel.setPressed(未知来源)javax.swing.DefaultButtonModel.fireActionPerformed(未知来源)的.actionPerformed(未知来源) javax.swing.JCompo中的.Component.processMouseEvent(未知来源) java.awt.Container上的java.awt.Component中的java.awt.Component.processEvent(未知源)中的nent.processMouseEvent(未知来源)java.awt.Container上的java.awt.Component.dispatchEventImpl(未知来源)。 java.awt.LightweightDispatcher.dispatchEvent上的java.awt.LightweightDispatcher.retargetMouseEvent(未知源)位于java.awt.LightweightDispatcher.dispatchEvent上的java.awt.Component.dispatchEvent(未知来源)处于java.awt.LightweightDispatcher.dispatchEvent上的java.awt.Component.dispatchEvent(未知来源)中的dispatchEventImpl(未知来源) java.awt.EventQueue.dispatchEventImpl上的java.awt.Component.dispatchEvent(未知来源)java.awt.Eindq.dispatchEventImpl(未知来源)at java.awt.EventQueue.dispatchEventImpl(未知来源) )java.awt.EventQueue.access $ 700(未知来源)java.awt.EventQueue $ 3.run(未知来源)java.awt.EventQueue $ 3.run(未知来源)java.security.AccessController.doPrivileged(Native)方法)在java.security.ProtectionDomain $ 1.doIntersectionPrivilege(未知来源 )java.security.Protevileue上的java.security.ProtectionDomain $ 1.doIntersectionPrivilege(未知来源)java.awt.EventQueue $ 4.run(未知来源)java.security.AccessController.doPrivileged上的java.jun(未知来源)方法)java.security.ProtectionDomain $ 1.doIntersectionPrivilege(Unknown Source)at java.awt.EventDueatch.dispatchEvent(Unknown Source)at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) )java.awt.EventDispatchThread.Hump上的java.awt.EventDispatchThread.pumpEventsForHierarchy(未知来源)java.awt.EventDispatchThread.pumpEvents(未知来源)java.awt.EventDispatchThread.run上的java.awt.EventDispatchThread.pumpEvents(未知来源)(未知来源)

编辑1: updateSource方法:

 @Override public void updateSources(){ cbAnalysisSources.addItem(DataManager.sources.get(DataManager.sources.size()-1)); } 

介绍Eclipse中的基本调试,因为这非常重要,几乎可以解决所有错误和错误。 有很多Eclipse可以帮助你,但我会向你展示基础知识,你可以从那里阅读和探索。 尽管如此,它仍然有用。

我制作了一段简单的代码来处理:

 public class Example { public static void main(String[] args) { int[] array = new int[] {12, 14, 523, 5423, 12, 0 ,14, -3, 521, 2}; int pos = 0; for (int i = 0; i < 16; i++) { array[i] = -1; pos = increment(pos); } } static int increment(int pos) { int num = pos + 1; return num; } } 

如果你运行它,它将抛出一个ArrayIndexOutOfBoundsException 。 要进行调试,我们需要在代码中的某处设置断点,我们认为问题始于此处,可能接近抛出exception的行。 断点背后的想法是,代码在到达用断点标记的行时将停止运行 。 通过双击相应行旁边的编辑器中的左侧栏输入断点(请参阅红色圆圈)。 您可以在不同的地方输入多个断点。 然后,单击“ Debug按钮(黄色圆圈)。 确保它不是“ Run按钮,因为这将忽略断点。

在此处输入图像描述

然后,您将进入Debug透视图,它提供不同的视图(我的视图从默认视图重新排列):

在此处输入图像描述

你在这里看到的是:

  1. 查看列出所有变量(包括字段,数组等)及其值。 对于对象(类实例和数组),您将有一个展开箭头来显示其类成员和属性。 只要其中一个值发生交流变化,它就会以黄色突出显示。
  2. 显示上面视图中所选行的值。 有些物体很长很复杂,所以在那里看它很方便。
  3. 普通的编辑器,但有一个荧光笔,可以显示代码所在的位置。 很快我们就会谈到这一点。 这里的代码位于断点处,因为这是第一次停止的地方。
  4. 只是控制台看到打印。
  5. 有关线程的信息。 当您运行multithreading程序时,它将列出所有线程及其状态。 在这里,您将看到线程main breakpoint at line 9被原因breakpoint at line 9 suspended ,这应该是它应该是的。

现在进入“调试本身”。 您将在“ Run菜单下找到许多选项,但有用的选项是:

  • F6 - step over在跳过方法调用时,这将前进到代码中的下一行。
  • F5 - step into :这将进入代码中的下一行并进入方法调用 。 请注意,如果您拥有JDK(或附带源代码的JRE),它将进入Oracle的库,这通常不是您想要的。 有时他们的代码非常复杂,如果你继续踩到它,你可能永远不会回来......
  • F8 - resume :这将运行代码,直到达到下一个断点。 例如,如果您在循环中运行,它可以是编辑器中的相同断点。
  • F7 - step return :这将运行代码,直到当前方法返回(如果适用)。
  • Ctrl-R - run to line :这将运行代码,直到放置插入符号的行。

示范:

  1. F6 F5 ,您将看到在视图1中,变量i被添加,因为它是在while循环中创建的。 它的值为0。
  2. F6 F5 ,您将在array[0]上看到黄色突出显示,其新值-1在代码中指定(您必须扩展数组变量)。
  3. F6 (将在下一次迭代时执行F5 ),现在pos被突出显示,因为该方法为其分配了新值。 调试器将运行回循环。
  4. 重复步骤1和2, iarray[1]将改变。
  5. F5 ,您将进入increment 。 请注意,由于所有其他变量都超出范围,因此仅显示局部变量 pos
  6. F6 F5 ,直到再次到达循环(第9行)。 您将被取出该方法。 观察pos变化。
  7. F8 ,代码将运行完整的迭代并再次停在断点处。 请注意值已更改。
  8. 将插入符号放在第17行并按Ctrl+R 代码将一直运行到第17行,就像踩到所有内容一样,直到达到它。
  9. F7 ,代码将一直运行,直到increment返回。 pos直到下一步才会更新,但i会突出显示,因为这是您第一次有机会看到for循环中所做的更改(第9行)。
  10. 继续使用F8运行代码,最终您会注意到它在第10行停止。这是因为如果您继续前进,将在此行引发exception。 它是一个自动断点,用于提醒您exception。
  11. F6一次,如果附加了代码,则将在Thread方法dispatchUncaughtException类中使用Oracle的代码。
  12. 再次按F6 ,将抛出exception并终止程序。 如果您只是正常运行代码,那么这就是您将要遇到的阶段。 但是,现在,您将能够确切地看到哪些变量何时以及如何更改,因此了解抛出exception的原因以及问题所在的位置要容易得多。

尝试在更复杂的情况下运行调试器,直到您感觉舒服为止。 您可以将pos更改为i以使程序更有趣。 这是

如何避免IndexOutOfBoundsexception。

如果您有任何疑问,请发表评论。