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);
}
}
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){}
}
}
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);
}
}
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:
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.
- Bert Bates, Kathy Sierra. Certificação Sun para programadores Java 5 - SCJP(Guia de Estudo)
- Class Scanner