【问题标题】:How-to avoid IndexOutOfBounds Exception when Dynamically Updating JComboBox (Debugging help)动态更新 JComboBox 时如何避免 IndexOutOfBounds 异常(调试帮助)
【发布时间】:2015-07-11 20:50:02
【问题描述】:

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

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

我有一个遵循单例模式的类 (DataManager)。此外,该类遵循观察者和工厂模式。 DataManager 是一个可观察的对象。观察到的数据格式如下:

public static List<Target> targets = new ArrayList<Target>();

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

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

其中一种形式是观察者对象,它观察 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<IObserve> targetObservers = new HashSet<IObserve>();
private static Set<IObserve> sourceObservers = new HashSet<IObserve>();
private static Set<IObserve> fluidObservers = new HashSet<IObserve>();

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 异常。在以下情况下会出现异常:
1.用户打开第一个表单,成功发起创建2个相同类型的预定义对象。
2、用户打开第二个表单;填写表格并在确认后(单击按钮)收到如下异常。

理想情况下,我希望在解决以下问题和解决下面所述的异常方面得到帮助。

例外:

线程“AWT-EventQueue-0”java.lang.IndexOutOfBoundsException 中的异常:索引:1,大小:1 在 java.util.ArrayList.rangeCheck(未知来源) 在 java.util.ArrayList.get(未知来源) 在 fprof.application.data.frame.manager.content.AnalysisCreatorPanel.updateSources(AnalysisCreatorPanel.java:99) 在 fprof.application.utility.IObservable.notifySourceObservers(IObservable.java:32) 在 fprof.application.data.manager.IDataManager.createSource(IDataManager.java:29) 在 fprof.application.data.frame.manager.content.SourceCreatorPanel$1.actionPerformed(SourceCreatorPanel.java:127) 在 javax.swing.AbstractButton.fireActionPerformed(未知来源) 在 javax.swing.AbstractButton$Handler.actionPerformed(未知来源) 在 javax.swing.DefaultButtonModel.fireActionPerformed(未知来源) 在 javax.swing.DefaultButtonModel.setPressed(未知来源) 在 javax.swing.plaf.basic.BasicButtonListener.mouseReleased(未知来源) 在 java.awt.Component.processMouseEvent(未知来源) 在 javax.swing.JComponent.processMouseEvent(未知来源) 在 java.awt.Component.processEvent(未知来源) 在 java.awt.Container.processEvent(未知来源) 在 java.awt.Component.dispatchEventImpl(未知来源) 在 java.awt.Container.dispatchEventImpl(未知来源) 在 java.awt.Component.dispatchEvent(未知来源) 在 java.awt.LightweightDispatcher.retargetMouseEvent(未知来源) 在 java.awt.LightweightDispatcher.processMouseEvent(未知来源) 在 java.awt.LightweightDispatcher.dispatchEvent(未知来源) 在 java.awt.Container.dispatchEventImpl(未知来源) 在 java.awt.Window.dispatchEventImpl(未知来源) 在 java.awt.Component.dispatchEvent(未知来源) 在 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.security.ProtectionDomain$1.doIntersectionPrivilege(未知来源) 在 java.awt.EventQueue$4.run(未知来源) 在 java.awt.EventQueue$4.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(未知来源)

编辑 1: updateSource 方法:

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

【问题讨论】:

    标签: java swing


    【解决方案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。要进行调试,我们需要在代码中我们认为问题开始的地方设置断点,可能靠近引发异常的行。 断点背后的想法是,代码将在到达标有断点的行时停止运行。通过双击编辑器中相应行旁边的左侧栏来输入断点(见红色圆圈)。您可以在不同的位置输入多个断点。然后,单击Debug 按钮(黄色圆圈)。确保它不是 Run 按钮,因为它会忽略断点。

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

    你在这里看到的是:

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

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

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

    演示:

    1. 按F5 或F6,您将看到在视图1 中,添加了变量i,因为它是在while 循环中创建的。它的值为 0 分配。
    2. 按F6 的F5,您将在array 的[0] 上看到一个黄色突出显示,其新值-1 已在代码中指定(您必须扩展数组变量)。
    3. 按F6(将在下一次迭代中执行F5),现在pos 被突出显示,因为该方法为其分配了一个新值。调试器将运行回循环。
    4. 重复步骤 1 和 2,i 和 array[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 行停止。这是因为如果您继续前进,该行将引发异常。它是一个自动断点,用于提醒您异常。
    11. 按一次F6,如果您附加了代码,您将被带到Thread 类dispatchUncaughtException 中的Oracle 代码。
    12. 再按F6,会抛出异常,程序会终止。如果您只是正常运行代码,这就是您所处的阶段。但是,现在您将能够准确地看到哪些变量在何时以及如何发生变化,因此了解引发异常的原因以及问题所在会容易得多。

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

    如何避免 IndexOutOfBounds 异常。

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

    【讨论】:

      猜你喜欢
      • 2016-03-10
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      相关资源
      最近更新 更多