Erro em métodos internos do java

Olá a todos! Venho me deparando com erros estranhos no java desde que mudei de sistema operacional. Antes eu usava windows 7 e não tinha os mesmos problemas.
Veja, já estou a 1 ano programando em java e esses métodos que estou usando já utilizei em diversos outros problemas parecidos e consegui executar.
Agora, estava fazendo o código do curso do Nélio alvez, usando a mesma versão java que ele, entretanto encontrei o erro dentro do while, aparentemente o while executa a condição mas ele está deixando passar mesmo se a condição não for satisfeita. Cheguei a esta conclusão tentando captar o dado que não deveria entrar e consegui com exito!

package genericoDelimitado.application;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import genericoDelimitado.entities.Product;
import genericoDelimitado.services.*;

public class Program {

	public static void main(String[] args) {

		List<Product> list = new ArrayList<>();

		String path = "/home/washington/Documentos/produtos.txt";

		try (BufferedReader br = new BufferedReader(new FileReader(path))) {

			String line = br.readLine();
			while (line != null) {
				
			String[] fields = line.split(",");
			if(fields.length == 0 || fields.length <= 1) {
				Product x = CalculationService.max(list);
				System.out.println("Max:");
				System.out.println(x);
				
			}else {
				System.out.println(fields[0].toString() + fields[1].toString());
				list.add(new Product(fields[0], Double.parseDouble(fields[1])));
				line = br.readLine();
							
			}
	
					
			}

			Product x = CalculationService.max(list);
			System.out.println("Max:");
			System.out.println(x);

		} catch (IOException e) {
			System.out.println("Error: " + e.getMessage());
		}

	}

}

Veja que dentro do if, eu coloquei o código que seria executado após while, mas ele nunca chegou a ser executado por conta que a linha vazia do arquivo estava entrando mesmo não sendo permitido pela condição. Com esse if consegui capturar o erro e identificar que era realmente isto que estava acontecendo.
Logo quando o código é executado, ele entra em um loop infinito uma vez que assim que ele lê todos os caracteres, ele entra nas linhas vazias e conseqüentemente no if, fazendo com que o código dentro do bloco seja executado até você forçar parada na ide. Detalhe, estou usando eclipse(primeira vez que uso, sempre usei netBeans)
Alguém tem uma ideia do que possa ser e como resolver este problema??

Aquele readLine dentro do else deveria estar fora dele.

Então, ao invés de deixar assim:

  } else {
    System.out.println(fields[0].toString() + fields[1].toString());
    list.add(new Product(fields[0], Double.parseDouble(fields[1])));
    line = br.readLine();
  }
}

Deixa assim:

  } else {
    System.out.println(fields[0].toString() + fields[1].toString());
    list.add(new Product(fields[0], Double.parseDouble(fields[1])));
  }
  line = br.readLine();
}
1 curtida

Qualquer computador, seja ele físico (o que vc usa), ou a máquina virtual Java, é uma máquina determinística. Não existe mágica ou exoterismo. É impossível um algoritmo que funcionava ontem ou há um milhão de anos parar de funcionar ou começar a funcionar errado para as mesmas entradas. Tenha certeza, em 99,99999999999999999999% das vezes é o programador que está errando, no caso você. É claro, existem falhas sistêmicas que podem existir, ou seja, um problema físico no processador ou na JVM, mas se esse for o caso, provavelmente o computador como um todo não vai funcionar direito, se é que vai funcionar.

1 curtida

Dessa maneira funcionou, porem, como estava dando erro no caso da condição do while aparentemente ser desconsiderada?

No código é visivel que dentro do while eu coloco um if parfa captar exatamente a condição que o while não deveria deixar passar, ou seja, enquanto não fosse nulo executasse. Porém, mesmo com essa condição ele lê diversas vezes linhas vazias.

O valor que sua condição depende só está sendo atualizado no else como o @wldomiciano já indicou. Vc tem um problema na lógica do seu algoritmo, ou seja, vc errou. Como você quer quer o while se comporte da forma que vc quer se o seu código está errado? Talvez se vc identar direito seu código isso já te ajude a entender melhor seu problema. Será que não é um pouco de exagero vc estar convencido que para algo tão trivial e simples a JVM esteja se comportando erroneamente? Sei que é meio pedante usar o argumento da autoridade, mas mesmo assim vou usar. Pode acreditar na gente, os poucos que ainda respondem aqui no GUJ sabem o que estão falando :wink:

1 curtida

Sim, nesse código específico a variável pega certinho quando você tira o a leitura do buffer do Else. O problema é que o algoritmo não tem if e nem Else. Isso eu usei apenas para captar a condição que não satisfaz o while. E sim, essa condição ainda está sendo captada. Mesmo eu usando a leitura do buffer depois do Else, ela capta a linha null. A diferença é que agora ela apenas capta uma vez e para, mas usando o algoritmo original mesmo, ele da um erro logo de início na captura desse null. Eu apenas coloquei o if para poder indentificar se realmente a condição que não satisfaz o while estava entrando dentro do bloco de execução e sim, ele está entrando.
O que o nosso amigo mostrou no algoritmo dele satisfaz o que eu queria, ele devolve o produto mais caro, entretanto, o while ainda deixa passar as linhas vazias do null.

Linhas vazias do null? Uma linha vazia não é nula, é uma string vazia. O BufferedReader retorna null quando chega no fim do arquivo. Talvez seja isso que vc não está entendendo e está misturando as coisas.

Pow, pode ser. Vou mudar a condição do while para ver se funciona. Eu achei que como uma linha vazia da um erro de null exception era entendida como tal. Vou fazer isso e ver o resultado. De qualquer forma obrigado por tudo.

Sem ver como está o arquivo, fica difícil adivinhar. Mas enfim, o que pode ter acontecido é que chegou em uma linha que não tem nenhuma vírgula, por isso o split retornou um array com tamanho 1 e entrou no if. E como dentro do if vc não lê mais nenhuma linha (pois o readLine está dentro do else), o programa entra em loop.

Aproveitando, geralmente costuma-se ler as linhas de um BufferedReader assim:

String line;
while ((line = br.readLine()) != null) { // lê a próxima linha e já vê se é null
    String[] fields = line.split(",");
    if (fields.length <= 1) { // testar se é igual a zero é redundante, pois se for zero, então será menor que 1
        Product x = CalculationService.max(list);
        System.out.println("Max:");
        System.out.println(x);
    } else {
        System.out.println(fields[0] + fields[1]); // não precisa chamar toString()
        list.add(new Product(fields[0], Double.parseDouble(fields[1])));
    }
}

Ou seja, (line = br.readLine()) != null lê a próxima linha, guarda o resultado em line e já testa se é nulo. Assim, vc não precisa mais chamar readLine dentro do loop, e garante que a cada iteração uma nova linha será lida.

Também mudei a condição para somente fields.length <= 1. Não precisa testar se é zero, pois se for zero, então será menor que 1 (e o length nunca é negativo, então só esse teste já basta).