Função retorna ArrayList vazio

Olá Pessoal, sou estudante novo em java e estou passando por um problema com arraylist, quando seleciono a função escolherJogo() por mais que tenha jogos ela me retorna uma lista vazia pq?

import java.util.*;
public class Sorteador {

    private static Random instance;

    private List<Integer> jogo = new ArrayList<>();
    private List<List<Integer>> Jogos = new ArrayList<>();

    public Sorteador() {
    }

    public static Random getInstance(){
        if (instance == null){
            return new Random();
        } else {
            return instance;
        }
    }

    public void SortearJogos(int qntJogos){
        for (int i = 0; i < qntJogos; i++){
            Jogos.add(new ArrayList<>());

            for (int j = 0; j < 6; j++){
                int numSorteado = getInstance().nextInt(61);
                if (jogo.size() > 0){
                    boolean check = true;
                    while (check){
                        if (numSorteado == 0 || jogo.contains(numSorteado)){
                            numSorteado = getInstance().nextInt(61);
                        } else {
                            check = false;
                        }
                    }
                }
                jogo.add(numSorteado);
            }
            System.out.printf("%d# Jogo: ", i + 1); System.out.println(jogo);
            Jogos.set(i, jogo);
            jogo.clear();
        }
    }

    public void escolherJogo(){
        if (Jogos.size() > 0){
            System.out.println("Jogo da sorte: " + Jogos.get(getInstance().nextInt(Jogos.size())));
        } else {
            System.out.println("Você precisa sortear jogos para escolher 1!!");
        }

    }
}

Aqui estás a limpar a tua lista. Vais ter sempre listas vazias

2 curtidas

eu uso o clear depois de ter atribuido a outra lista “Jogos” e é dessa lista que a função escolherJogo tenta puxar.

tanto que quando sorteio mais jogos minha lista tem x posições e todas aparecem preenchidas no debugger

Na seu objeto Jogos você está sempre inserindo exatamente o mesmo objeto jogo e está sempre limpando esse objeto jogo.

Então na real Jogos contém o mesmo objeto vazio jogo em cada uma de suas posições.

1 curtida

Já explicaram o seu erro, mas apenas para detalhar melhor.

Jogos.add(new ArrayList<>());

Aqui vc adiciona um novo ArrayList em Jogos. Mas depois vc faz:

Jogos.set(i, jogo);

Isso sobrescreve a lista que havia sido inserida, substituindo-a por jogo.

Só que jogo é uma referência para uma lista, então no fim vc está inserindo a mesma referência várias vezes em Jogos. No final, Jogos terá várias referências para a mesma lista jogo. E como vc ainda faz jogos.clear(), isso limpa a lista, e no final Jogos tem várias referências para uma lista vazia.


Isso é porque vc imprime jogo antes de chamar clear(). Mas tente colocar System.out.println(Jogos) depois do for pra ver o que acontece: ele vai mostrar todas as listas vazias.


Outra coisa, para gerar números aleatórios sem repetição (como a amostragem é pequena: de 1 a 60), uma forma mais simples é simplesmente embaralhar todos os números e pegar os 6 primeiros (também conhecido como Algoritmo de Fisher-Yates).

Só que além disso, também precisa verificar se os 6 números sorteados já não estão na lista de Jogos. Pra facilitar essa verificação, troquei List por Set (e usei TreeSet, que já deixa os números em ordem). Além disso, isso já serve também para deixar indicado que os números não se repetem (um Set, por definição, não permite elementos repetidos).

Por fim, sugiro que siga as convenções de nomenclatura da linguagem: nomes de variáveis e métodos começam com minúscula, e constantes (variáveis estáticas e final), com NOMES_DESSE_JEITO.

Enfim, minha sugestão:

public class Sorteador {
    // não precisa de getInstance(), inicialize o Random aqui mesmo
    private static final Random RAND = new Random();
    // lista de todos os números que podem ser sorteados
    private List<Integer> numeros = new ArrayList<>();
    // quantidade de números por sorteio
    private int qtdPorSorteio;
    private List<Set<Integer>> jogos = new ArrayList<>();

    // sorteia números entre min e max, e com determinada quantidade de números por sorteio
    public Sorteador(int min, int max, int qtdPorSorteio) {
        for (int i = min; i <= max; i++) {
            this.numeros.add(i);
        }
        this.qtdPorSorteio = qtdPorSorteio;
    }

    public void sortearJogos(int qntJogos) {
        // limpa os jogos atuais
        this.jogos.clear();
        // sorteia novos
        int i = 1;
        while (this.jogos.size() < qntJogos) {
            Collections.shuffle(this.numeros, RAND); // embaralha os números e pega os N primeiros (Fisher-Yates)
            // pega os primeiros e adiciona na lista de jogos
            Set<Integer> jogo = new TreeSet<>(this.numeros.subList(0, this.qtdPorSorteio));
            if (! this.jogos.contains(jogo)) {
                // só adiciona se não existe nenhum outro sorteio com os mesmos números
                // por isso usei Set, que facilita muito essa comparação
                // (com listas, precisaria ordenar o jogo antes de usar contains)
                this.jogos.add(jogo);
                System.out.printf("%d# Jogo: %s\n", i, jogo);
                i++;
            }
        }
    }

    public void escolherJogo() {
        if (this.jogos.size() > 0) {
            System.out.println("Jogo da sorte: " + this.jogos.get(RAND.nextInt(this.jogos.size())));
        } else {
            System.out.println("Você precisa sortear jogos para escolher 1!!");
        }
    }
}

Adicionei uns parâmetros para deixar mais flexível. Pro seu caso (sortear 6 números entre 1 e 60), seria assim:

// números de 1 a 60, e 6 números por sorteio
Sorteador sorteador = new Sorteador(1, 60, 6);

sorteador.sortearJogos(4);
sorteador.escolherJogo();

Desta forma fica mais flexível, pois dá para usar a mesma classe para outros tipos de sorteio. Por exemplo, se for para a Quina (5 números de 1 a 80), bastaria usar new Sorteador(1, 80, 5).


Mas se quiser continuar usando List em vez de Set basta mudar para:

private List<List<Integer>> jogos = new ArrayList<>();

E o loop que sorteia os jogos mudaria para:

// sorteia novos
int i = 1;
while(this.jogos.size() < qntJogos) {
    Collections.shuffle(this.numeros, RAND); // embaralha os números e pega os N primeiros (Fisher-Yates)

    // pega os primeiros e adiciona na lista de jogos
    List<Integer> jogo = new ArrayList<>(this.numeros.subList(0, this.qtdPorSorteio));
    Collections.sort(jogo); // precisa ordenar, senão o contains não detecta jogos duplicados (caso os números estejam em ordem diferente)
    if (! this.jogos.contains(jogo)) {
        // só adiciona se não existe nenhum outro sorteio com os mesmos números
        this.jogos.add(jogo);
        System.out.printf("%d# Jogo: %s\n", i, jogo);
        i++;
    }
}

Precisa ordenar o jogo porque senão o contains não verifica jogos duplicados. Por exemplo, se um jogo for [1, 2, 3, 4, 5, 6] e outro for [6, 5, 4, 3, 2, 1], ele só detecta que o jogo já existe em jogos se os números estiverem na mesma ordem (com Set não tem esse problema).

2 curtidas