一个死循环导致的栈溢出实例:StackOverFlowError

  有一个功能,要用复选框组做成单选框效果,如果有三个复选框 CheckBox ,并且保证每次只能选中一个。刚开始添加了以下的值改变后的监听方法 addValueChangeListener ,却导致了栈溢出:

 1 public static void checkBoxAddChangeListener(CheckBox checkBox1, CheckBox checkBox2, CheckBox checkBox3){
 2     checkBox1.addValueChangeListener(e -> {
 3         checkBox2.setValue(!checkBox1.getValue());
 4         checkBox3.setValue(!checkBox1.getValue());
 5     });
 6 
 7     checkBox2.addValueChangeListener(e -> {
 8         checkBox1.setValue(!checkBox2.getValue());
 9         checkBox3.setValue(!checkBox2.getValue());
10     });
11 
12     checkBox3.addValueChangeListener(e -> {
13         checkBox1.setValue(!checkBox3.getValue());
14         checkBox2.setValue(!checkBox3.getValue());
15     });
16 }

 

  思考上面代码的逻辑,假如现在第二个复选框是选中状态,此时再选中了第一个复选框,会触发第一个复选框的监听事件,第二、三个复选按钮就变成了未选中状态。因为第二个复选框的状态改变了,会触发它的监听事件,此时第一、三个复选框会变成选中状态。因为第一个已经是选中状态了,所以不会触发值改变的监听器。但是第三个复选框的状态却变了,触发监听器事件,把第一、二个监听器变成未选中状态。此时会再次触发第一个复选框的监听器事件。如此往复循环,StackOverFlowError

  正确做法之一就是,不要在值改变的时候就触发事件,要在复选框的值变成选中状态时,触发一次事件就好了。添加以下判断。

 1 public static void checkBoxAddChangeListener(CheckBox checkBox1, CheckBox checkBox2, CheckBox checkBox3){
 2     checkBox1.addValueChangeListener(e -> {
 3         if(checkBox1.getValue()){
 4             checkBox2.setValue(false);
 5             checkBox3.setValue(false);
 6         }
 7     });
 8 
 9     checkBox2.addValueChangeListener(e -> {
10         if(checkBox2.getValue()){
11             checkBox1.setValue(false);
12             checkBox3.setValue(false);
13         }
14     });
15 
16     checkBox3.addValueChangeListener(e -> {
17         if(checkBox3.getValue()){
18             checkBox1.setValue(false);
19             checkBox2.setValue(false);
20         }
21     });
22 }

 

  这段代码还可以优化成一组复选框里只能选中一个值的方法,如下: 

public static void checkBoxAddChangeListener(List<CheckBox> list){
    for(int i=0; i<list.size(); i++){
        CheckBox checkBox = list.get(i);
        checkBox.addValueChangeListener(e -> {
            if(checkBox.getValue()){
                for (CheckBox tmp : list) {
                    if (tmp == checkBox) {
                        continue;
                    }
                    tmp.setValue(false);
                }
            }
        });
    }
}

  


 附录:

  但是最开始的错误方法,如果只有两个CheckBox,就不会报错了 

public static void checkBoxAddChangeListener(CheckBox checkBox1, CheckBox checkBox2){
    checkBox1.addValueChangeListener(e -> {
        checkBox2.setValue(!checkBox1.getValue());
    });

    checkBox2.addValueChangeListener(e -> {
        checkBox1.setValue(!checkBox2.getValue());
    });
}

 

  原因是:这两个监听器,每一个只能触发一个。
  假如开始第二个复选框是选中状态,此时选中第一个复选框,触发第一个复选框的监听事件,把第二个复选框变成未选中状态。再触发第二个复选框的监听事件,此时把第一个复选框变成了选中状态。但是因为第一个复选框本身已经是选中状态了,所以它的值并没有改变,所以不会触发监听器事件。

  原创文章,欢迎转载,转载请注明出处!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值