You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java乐透彩票类LinhaCartao访问ArrayList索引1抛出越界异常

简易乐透游戏开发问题

项目结构

开发的简易乐透彩票游戏共包含3个功能类:

  • LinhaCartao:彩票行类,负责管理单条彩票行的号码集合与相关操作
  • NumeroLoto:彩票号码实体类,封装号码数值、是否开出状态及对应读写方法
  • JogoLoto:程序入口测试类,用于验证功能逻辑

预期业务逻辑

实例化LinhaCartao时传入5个用户选定的号码,先存入holder临时列表,随后遍历每个号码,根据号码所属数值区间(1-9对应索引0、10-19对应索引1,依次类推至80-89对应索引8),将号码插入到初始化容量设为9的ArrayList<NumeroLoto>类型Nums集合的对应索引位置。

异常现象

传入参数(1, 20, 45, 58, 71)调用LinhaCartao构造方法时,执行到判断Nums.get(1) == null的代码分支抛出IndexOutOfBoundsException,异常提示为Index 1 out of bounds for length 1。


附完整代码与异常信息

LinhaCartao 类

package jogoloto;
import java.util.ArrayList;

/**
 *
 * @author Nuno
 */
public class LinhaCartao {
    ArrayList<NumeroLoto> Nums;
    ArrayList<Integer> holder;

    public LinhaCartao(int n1, int n2, int n3, int n4, int n5) {
        Nums = new ArrayList<>(9);
        holder = new ArrayList<>();
        holder.add(n1);
        holder.add(n2);
        holder.add(n3);
        holder.add(n4);
        holder.add(n5);
            for(int n : holder){ 
                if(Nums.isEmpty() && n >=1 && n<=9 || 
Nums.get(0) == null && n >=1 && n<=9){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(0,num);
                    
                }
                else if(Nums.isEmpty() && n >=10 && n<=19 || 
Nums.get(1) == null && n >=10 && n<=19){ // 异常抛出位置
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(1,num);
                    
                }
                else if(Nums.isEmpty() && n >=20 && n<=29 ||
Nums.get(2) == null && n >=20 && n<=29){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(2,num);
                    
                }
                else if(Nums.isEmpty() && n >=30 && n<=39 || 
Nums.get(3) == null && n >=30 && n<=39){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(3,num);
                    
                }
                else if(Nums.isEmpty() && n >=40 && n<=49 || 
Nums.get(4) == null && n >=40 && n<=49){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(4,num);
                    
                }
                else if(Nums.isEmpty() && n >=50 && n<=59 || 
Nums.get(5) == null && n >=50 && n<=59){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(5,num);
                    
                }
                else if(Nums.isEmpty() && n >=60 && n<=69 || 
Nums.get(6) == null && n >=60 && n<=69){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(6,num);
                    
                }
                else if(Nums.isEmpty() && n >=70 && n<=79 || 
Nums.get(7) == null && n >=70 && n<=79){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(7,num);
                    
                }
                else if(Nums.isEmpty() && n >=80 && n<=89 || 
Nums.get(8) == null && n >=80 && n<=89){
                    NumeroLoto num = new NumeroLoto(n);
                    Nums.add(8,num);
                    
                }
                else System.out.println("N invalido");    
            }
    }
    
    public void imprimeLinha(){
        for(int i = 0; i<9; i++){
            if(Nums.get(i).getNumero()>0){
                System.out.println(":"+Nums.get(i).getNumero()+":");
            }
            else if(Nums.get(i)== null){
                System.out.println(":_:");
            }
        }
    }
    
    public void marcaNumeroAnunciado(int numero){
        for(NumeroLoto n : Nums){
            if(n.getNumero()==numero){
                n.setSaiu(true);
            }
        }
    }
    
    public int quantosNumerosPorMarcar(){
        int count = 0;
        for(NumeroLoto n : Nums){
            if(n.getEstado()==false){
                count++;
            }
        }
        return count;
    }
    
    public boolean verificaLinhaCompleta(){
        int count = 0;
        for(NumeroLoto n : Nums){
            if(n.getEstado()==true){
                count++;
            }
            if(count==5){
                return true;
            }
        }
        return false;
    }
    
    public int limpaLinha(){
        int count = 0;
        for(NumeroLoto n : Nums){
            if(n.getEstado()==true){
                count++;
                Nums.remove(n);
            }
        }
        return count;
    }
}

NumeroLoto 类

package jogoloto;

/**
 *
 * @author Nuno
 */
public class NumeroLoto {
    int numero;
    public boolean saiu;

    public NumeroLoto(int numero) {
        this.numero = numero;
        saiu = false;
    }

    public int getNumero() {
        return numero;
    }
    
    public boolean getEstado(){
        return saiu;
    }

    public void setSaiu(boolean saiu) {
        this.saiu = saiu;
    }  
}

JogoLoto 入口类

public class JogoLoto {

    public static void main(String[] args) {
        LinhaCartao l = new LinhaCartao(1, 20, 45, 58, 71); // 构造方法调用时触发异常
        l.imprimeLinha();
        l.quantosNumerosPorMarcar();
    }
    
}

异常栈轨迹

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
    at java.base/java.util.Objects.checkIndex(Objects.java:359)
    at java.base/java.util.ArrayList.get(ArrayList.java:427)
    at jogoloto.LinhaCartao.<init>(LinhaCartao.java:30)
    at jogoloto.JogoLoto.main(JogoLoto.java:14)
C:\Users\Nuno\AppData\Local\NetBeans\Cache\14\executor-snippets\run.xml:111: The following error occurred while executing this line:
C:\Users\Nuno\AppData\Local\NetBeans\Cache\14\executor-snippets\run.xml:68: Java returned: 1
BUILD FAILED (total time: 0 seconds)

问题原因
  1. ArrayList初始容量≠实际元素数量:new ArrayList<>(9)只是给底层数组预分配了9个位置的内存,初始化完成后列表实际长度为0,不会自动填充9个null,只有调用add()方法才会增加实际元素长度。处理第一个号码1时,将元素add到索引0位置,此时列表实际长度只有1,仅索引0是合法可访问的。
  2. 逻辑运算符优先级错误:&&运算优先级高于||,分支判断没有加括号,实际执行逻辑和预期不符。处理第二个号码20时,Nums已经非空,第一个if分支不成立,走到第二个else if时,会直接执行Nums.get(1)的判断,而此时列表长度只有1,访问索引1直接触发越界异常。
  3. 其他隐藏问题:
    • 直接调用add(index, element)向非连续索引插入元素会持续触发越界,因为add不会自动补空位,要求index必须≤当前列表长度
    • imprimeLinha方法先调用Nums.get(i).getNumero()再判断元素是否为null,会触发空指针
    • limpaLinha方法在for-each遍历列表时直接调用remove删除元素,会触发并发修改异常
修复方案
  1. 初始化Nums时先填充9个null,保证索引0-8都可正常访问:
Nums = new ArrayList<>(9);
for (int i = 0; i < 9; i++) {
    Nums.add(null);
}
  1. 去掉冗余的9个重复分支,直接通过公式计算号码对应的索引,用set方法替换对应位置的null值,避免add导致的索引问题:
for(int n : holder){
    if(n < 1 || n > 89){
        System.out.println("N invalido");
        continue;
    }
    int idx = (n - 1) / 10; // 自动计算对应区间索引,无需手写判断
    if(Nums.get(idx) == null){
        Nums.set(idx, new NumeroLoto(n));
    }
}
  1. 修正imprimeLinha的空指针问题,先判空再读取属性:
public void imprimeLinha(){
    for(int i = 0; i<9; i++){
        NumeroLoto num = Nums.get(i);
        if(num == null){
            System.out.println(":_:");
        } else {
            System.out.println(":"+num.getNumero()+":");
        }
    }
}
  1. 修正limpaLinha的遍历删除问题,使用迭代器遍历删除,避免并发修改异常。

内容的提问来源于stack exchange,提问作者nuno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:48:15