O Java Scanner hasNext () vs. hasNextLine ()
1. Visão geral
A classeScanner é uma ferramenta útil que pode analisar tipos e strings primitivos usando expressões regulares e foi introduzida no pacotejava.util em Java 5.
Neste breve tutorial, falaremos sobre seus métodoshasNext()ehasNextLine(). Mesmo que esses dois métodos possam parecer muito semelhantes no início, eles estão fazendo verificações bastante diferentes.
2. hasNext()
2.1. Uso básico
O métodoThe hasNext() verifica seScanner tem outro token em sua entrada. A Scanner breaks its input into tokens using a delimiter pattern, which matches whitespace by default. Ou seja,hasNext() verifica a entrada e retornatrue se tiver outro caractere diferente de espaço em branco.
Também devemos observar alguns detalhes sobre o delimitador padrão:
-
Os espaços em branco incluem não apenas o caractere de espaço, mas também o espaço da tabulação ( ), avanço de linha ( ) eeven more characters
-
Caracteres de espaço em branco contínuos são tratados como um único delimitador
-
As linhas em branco no final da entrada não são impressas - ou seja,hasNext() retornafalse para linhas em branco
Vamos dar uma olhada em um exemplo de comohasNext() funciona com o delimitador padrão. Primeiro, vamos preparar uma string de entrada para nos ajudar a explorar o resultado da análise de Scanner:
String INPUT = new StringBuilder()
.append("magic\tproject\n")
.append(" database: oracle\n")
.append("dependencies:\n")
.append("spring:foo:bar\n")
.append("\n") // Note that the input ends with a blank line
.toString();
A seguir, vamos analisar a entrada e imprimir o resultado:
Scanner scanner = new Scanner(INPUT);
while (scanner.hasNext()) {
log.info(scanner.next());
}
log.info("--------OUTPUT--END---------")
Se executarmos o código acima, veremos a saída do console:
[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring:foo:bar
[DEMO]--------OUTPUT--END---------
2.2. Com delimitador personalizado
Até agora, vimoshasNext() com o delimitador padrão. A classeScannerprovides a useDelimiter(String pattern) method que nos permite alterar o delimitador. Assim que o delimitador for alterado, o métodohasNext() fará a verificação com o novo delimitador em vez do padrão.
Vamos ver outro exemplo de comohasNext() andnext() funciona com um delimitador personalizado. Reutilizaremos a entrada do último exemplo.
Depois que o scanner analisa um token correspondente à string “dependencies:“, vamos alterar o delimitador para dois pontos (: ) para que possamos analisar e extrair cada valor das dependências:
while (scanner.hasNext()) {
String token = scanner.next();
if ("dependencies:".equals(token)) {
scanner.useDelimiter(":");
}
log.info(token);
}
log.info("--------OUTPUT--END---------");
Vamos ver a saída resultante:
[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]
spring
[DEMO]foo
[DEMO]bar
[DEMO]--------OUTPUT--END---------
Ótimo! Extraímos com sucesso os valores em “dependencies“, no entanto, existem algunsunexpected line-break problems. Veremos como evitá-los na próxima seção.
2.3. Comregex como Delimitador
Vamos revisar a saída da última seção. Primeiro, notamos que há uma quebra de linha ( ) antes de "spring". Alteramos o delimitador para “:” depois que o token“dependencies:” foi buscado. A quebra de linha após “dependencies:” agora se torna parte do próximo token. Portanto,hasNext() retornoutruee a quebra de linha foi impressa.
Pela mesma razão, o avanço de linha após “hibernate” e a última linha em branco tornam-se parte do último token, então duas linhas em branco são impressas junto com “hibernate“.
Se conseguirmos definir dois pontos e espaços em branco como delimitador, os valores de "dependências" serão analisados corretamente e nosso problema será resolvido. Para conseguir isso, vamos mudar a chamadauseDelimiter(“:”):
scanner.useDelimiter(":|\\s+");
O “:|\s+” aqui é uma expressão regular correspondendo a um único “:” ou um ou mais caracteres de espaço em branco. Com essa correção, a saída se transforma em:
[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring
[DEMO]foo
[DEMO]bar
[DEMO]--------OUTPUT--END---------
3. hasNextLine()
O métodohasNextLine() verifica se há outra linha na entrada do objetoScanner, não importa se a linha está em branco ou não.
Vamos pegar a mesma entrada novamente. Desta vez, adicionaremos números de linha na frente de cada linha na entrada usando os métodoshasNextLine()enextLine():
int i = 0;
while (scanner.hasNextLine()) {
log.info(String.format("%d|%s", ++i, scanner.nextLine()));
}
log.info("--------OUTPUT--END---------");
Agora, vamos dar uma olhada em nossa saída:
[DEMO]1|magic project
[DEMO]2| database: oracle
[DEMO]3|dependencies:
[DEMO]4|spring:foo:bar
[DEMO]5|
[DEMO]--------OUTPUT--END---------
Como esperávamos, os números das linhas são impressos e a última linha em branco também está lá.
4. Conclusão
Neste artigo, aprendemos que o métodohasNextLine() deScanner verifica se há outra linha na entrada, não importa se a linha está em branco ou não, enquantohasNext() usa um delimitador para verificar se há outro token.
Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.