Existem situações onde nós, programadores, recebemos a “simples” tarefa de abrir um arquivo, ler um texto com 50 mil palavras, quebrar o texto em partes menores e utilizar estas partes para configurar Beans e coisas do tipo. Em casos como esse não se deve reinventar a roda e tentar criar algo totalmente revolucionário que irá mudar o jeito que todos os programadores executam esta tarefa. Aliás, sim, você pode tentar fazer isto. Porém, saiba que estará “perdendo tempo”, uma vez que uma solução para isto já existe e é muito simples de ser utilizada. Java oferece a seus programadores os tokens que, basicamente, executam todas as tarefas citadas anteriormente.

Utilizando o cenário anterior, suponhamos que precisamos abrir um arquivo chamado Teste.txt, fazer uma lida em seu texto, quebrá-lo em partes e atribuí-las a determinados objetos para serem utilizados posteriormente em outras partes do nosso sistema. Parece complicado, né?! Mas não é.

Neste artigo, abordaremos uma das classes que oferecem este tipo de serviço: Scanner.

Scanner

Antes de tentarmos solucionar o problema anterior, daremos uma olhada no exemplo de Scanner que existe no livro de certificação para podermos exemplificar bem e absorvermos o conceito da Classe.


import java.util.Scanner;


public class Testando {

	public static void main(String[] args)
	{
		boolean b2, b;
		int i;
		String s, hits = "";
		
		// Criação dos Scanners.
		Scanner s1 = new Scanner(args[0]);
		Scanner s2 = new Scanner(args[0]);
		
		// Verificação do primeiro scanner
		while (b = s1.hasNext())
		{
			s = s1.next(); 
			hits += "s";
		}
		
		// VErificação do segundo scanner
		while (b = s2.hasNext())
		{
			if (s2.hasNextInt())   // O próximo é um Integer?
			{
				i = s2.nextInt();
				hits += "i";
			}else if (s2.hasNextBoolean()) // O próximo é um Boolean?
			{
				b2 = s2.nextBoolean();
				hits += "b";
			}else
			{
				s2.next(); 				// Ou nenhum dos anteriores?
				hits += "s2";
			}
		}
		
		System.out.println("hits " + hits);
	}
}
Listagem 1. Exemplo de Scanner do Livro

Tendo em mente que os argumentos passados para a classe anterior foram “1 true 34 hi”, a reposta no console será “hits ssssibis2”.

Entendendo o fluxo do exemplo do livro

  • Por padrão, o delimitador padrão do Scanner é espaço. Sendo assim, a cada espaço encontrado na String, será separado um novo valor pelo Scanner. Esse delimitador pode ser alterado por outros tipos, digamos, mais específicos.
  • Foram criados dois scanners, ambos recebendo o valor do primeiro slot do vetor que veio dos argumentos.
  • A partir do primeiro Scanner, foi verificado se existia qualquer valor dentro da string. Ou seja, se o Scanner encontrasse algum qualquer valor, utilizando o delimitador de espaço, entraria no while até que o último fosse encontrado.
  • Utilizando o segundo Scanner, foi feita uma verificação mais específica na String. Quando o próximo valor a ser utilizado era um Integer, uma letra “i” era pra ser adicionada a variável hints; Quando era um boolean, uma letra “b”; Quando não era nem Integer e nem Boolean, um “s2”.
  • Com isso, obtivemos o resultado “hits ssssibis2”.

O exemplo serviu para mostrar uma utilização básica e outra mais específicas da classe Scanner.

Solucionando o problema proposto no artigo:

Para solucionar o problema proposto no início do artigo, nós poderíamos utilizar String.split(). Mas, é mais prático e eficiente que utilizemos Scanner devido a sua diversidade de funcionalidades que auxiliarão o programador na hora de execução da operação. Então, mãos na massa!

Teremos um arquivo chamado Teste.txt que terá, como conteúdo, o texto; “Tiago 23 Argolo”.


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;


public class Tester {
	
	public static void main(String[] args) {

		File f = new File("Teste.txt");     
		
		try
		{
			FileWriter fw = new FileWriter(f);   // Cria o nosso arquivo
			fw.append("Tiago 23 Argolo");	 	 // Seta seu conteúdo.
			fw.flush();
			fw.close();
		}catch(IOException e){}
			
		
	}

}
Listagem 2. Criação do arquivo Teste.txt e setando seu conteúdo

Antes de utilizarmos o Scanner nesta classe, segue um resumo do livro da certificação Java explicando as suas funcionalidades:

  • Scanners podem ser construídos usando-se arquivos, streams ou Strings como fonte.
  • A tokenização é realizada dentro de um loop, para que você possa finalizar o processo a qualquer momento.
  • Os tokens podem ser convertidos automaticamente para os seus tipos primitivos apropriados.

Scanner na prática!

Iniciaremos com a utilização da classe Scanner, então.


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;


public class Tester {
	
	public static void main(String[] args) {

		File f = new File("Teste.txt");
		String linha = ""; String inteiro = ""; String texto = "";
		Scanner s;
		
		try
		{
			FileWriter fw = new FileWriter(f);   // Cria o nosso arquivo
			fw.append("Tiago 23 Argolo");	 	 // Seta seu conteúdo.
			fw.flush();
			fw.close();
		}catch(IOException e){}
			
		// Obtendo o arquivo e suas informações
		
		try
		{
			FileReader fr = new FileReader(f);			
			BufferedReader br = new BufferedReader(fr);
			linha = br.readLine();
			
			s = new Scanner(linha);	
			boolean b;
			
			while (b = s.hasNext())	// verifica se tem outro valor.
			{
				if (s.hasNextInt())   // verifica se o próximo valor é inteiro
				{
					inteiro += " " + s.next();
				}else				//   CAso não for inteiro.
				{
					texto += " " + s.next();
				}
			}
			 
		}catch(IOException e){}

		// A partir daqui, posso utilizar ambas a variáveis em outros objetos
		// que serão utilizados pela minha aplicação.
		
		System.out.println("Textos" + texto +"\nInteiros: " + inteiro);
	}

}
Listagem 3. Utilização do Scanner na classe Teste.java

Nesse código foram utilizadas as formas mais práticas, para que a explicação também possa ser simples. Então, não estranhe se encontrar algo válido, porém não recomendado na classe Teste.java

Explicando o código da classe Teste.java

  • Foi criado um Scanner com um Objeto String que possui o conteúdo do arquivo Teste.txt
  • Através deste Scanner, verificamos dentro do objeto String se existe um próximo valor.
  • Caso positivo, verifique se o valor é inteiro ou não. Caso seja inteiro, escreva o valor na variável inteiro. Caso seja qualquer outra coisa que não seja inteiro, escreva na variável texto o seu valor.
  • Exiba ambas as variáveis no final.

Eis o resultado da classe Teste.java:

Execução da classe Teste.java
Figura 1. Execução da classe Teste.java

Esta foi uma exemplificação simples, porém prática. Imaginemos utilizar esse poder de busca em algo mais sofisticado, como uma matriz contendo milhares e milhares de linhas. É necessário que seja transferido este exemplo para algo mais complexo. Algo que, talvez, você use em seu trabalho e agora saiba como melhorar o procedimento, torná-lo mais rápido e eficiente.

Com isto, termino o meu artigo sobre tokenização utilizando Scanner, uma ferramenta muito importante na linguagem Java que pode ser aplicada em diversas situações bem distintas. Espero ter ajudado na compreensão do assunto e estimulado o seu uso no dia-a-dia em vossos ambientes de trabalho.

Referências:
  • Bert Bates, Kathy Sierra. Certificação Sun para programadores Java 5 - SCJP(Guia de Estudo)
  • Class Scanner