Let’s run some tests to see what happens to each reading done by Scanner
, and so understand why "works" in some cases and in others not.
First let’s see what happens when you read the number before the name. To better understand, I put a System.out.println
to see the value of each variable right after it is read by Scanner
:
idade = ler.nextInt();
System.out.println("idade=" + idade);
nome = ler.nextLine();
System.out.println("nome=" + nome);
If you type 10 Fulano
, what happens is this:
nextInt
read the number 10
nextLine
reads from the position in which it stopped earlier (i.e., right after the 10
) until the end of the line
So the exit is:
idade=10
nome= Fulano
Note that the name has a space at the beginning (before the F
), since the nextLine()
begins reading the position in which it stopped (which is just after the 10
), and ends at the end of the line.
Now, if you reverse the order in which the data is read:
nome = ler.nextLine();
System.out.println("nome=" + nome);
idade = ler.nextInt();
System.out.println("idade=" + idade);
If you type Fulano 10
, the call of nextLine()
will get whole line (the variable nome
will have all the string Fulano 10
) and the code will print:
nome=Fulano 10
When you type the next line (for example, Ciclano 20
), the code will try to interpret it with nextInt()
, but how this line starts with Ciclano
and this is not a number, will occur the InputMismatchException
.
You can even change the call from nextLine()
for next()
, that instead of picking up the whole line, it only picks up to space (which is the delimiter default, according to the documentation):
nome = ler.next();
System.out.println("nome=" + nome);
idade = ler.nextInt();
System.out.println("idade=" + idade);
Now if you type Fulano 10
, the name will be "John Doe" and the age will be 10.
But the above solution assumes that the name has no spaces. If you type Fulano de Tal 10
, for example, the next()
will just take Fulano
, and the nextInt()
will try to read the excerpt de
as a number, and will give error.
In that case, it might be easier to read the whole line with nextLine()
, make a split
and see if the number is at the beginning or the end (and then consider that the name is what’s left).
Another detail is that you do not need to compare the name of the elder within the loop. If you want to know the age of the oldest, just compare the ages and then you keep the respective name. In the end it looks like this:
int idade = 0;
int cont = 0;
int maiorIdade = -1;
String nome, maisVelho = "";
Scanner ler = new Scanner(System.in);
while (cont < 5) {
// divide a linha em partes, separadas por espaço
String[] partes = ler.nextLine().split(" ");
try {
// ver se o número está no começo
idade = Integer.parseInt(partes[0]);
// juntar as partes restantes para compor o nome (do segundo ao último elemento)
nome = String.join(" ", Arrays.copyOfRange(partes, 1, partes.length));
} catch (NumberFormatException e) {
// número está no final
idade = Integer.parseInt(partes[partes.length - 1]);
// pegar do primeiro ao penúltimo elemento (juntar para obter o nome)
nome = String.join(" ", Arrays.copyOfRange(partes, 0, partes.length - 1));
}
System.out.println("nome=" + nome);
System.out.println("idade=" + idade);
if (idade > maiorIdade) {
maisVelho = nome;
maiorIdade = idade;
}
cont++;
}
System.out.println("mais velho=" + maisVelho + ", idade=" + maiorIdade);
Now it doesn’t matter if the line is typed as 10 Fulano de Tal
or Ciclano da Silva 30
, because the code tries to verify the number at the beginning, and if it does not give, checks at the end (and if it is not at the end, will give error, which you can choose to capture by placing another try
/catch
, if you want).
Then the method of join
(available from Java 8) joins the other parts to form the name.
And the if
who compares the ages do not need to compare the name, because you only need to check if in the new data entered the age is greater (and then you arrow the respective name).
Another alternative, in case the name comes first and can have spaces, is to change the tab default that the Scanner
uses:
Scanner ler = new Scanner(System.in).useDelimiter(" (?=\\d)|\\n");
while (cont < 5) {
nome = ler.next();
idade = ler.nextInt();
... etc
Thus, the method next
uses the specified regular expression as a separator. In this case, it has a space (note that there is a space after the opening of the quotation marks) and then we have a Lookahead (the stretch (?=\\d)
), that serves to verify if something exists after the current position. This indicates that I use as separator a space, as long as it has a digit (\\d
) soon after.
But regex also uses alternation (the character |
), indicating that you can also use the \n
(line break) as separator.
That is, the method next()
reads everything until you find a space (as long as it’s followed by number) or a line break. With this, lines like Fulano de Tal 10
are read correctly: first the next()
capture the string Fulano de Tal
and then nextInt()
capture the 10
.
But if you want a more generic solution, in which it does not matter if the number comes at the beginning or at the end, better use the previous solution, with split
.
Just to warn you, comparing strings to operator is not a good one, I recommend using the string class equals method.
– Filipe Farias
Probably the error is at the time of reading the age, because it is expected number and was typed text. The order in which Voce enters the data must be the same as the order in which the variables are completed.
– Fabio Gonçalves Dos Santos