Por que precisamos de uma instância da classe Scanner para obter uma entrada em Java?

10

Java é orientado a objetos, mas, por que precisamos criar um objeto da classe Scanner para obter entrada? Os next()métodos, por exemplo, não poderiam ser apenas estáticos?

C me parece bem mais simples quando você usa scanf(), gets()ou fgets(). Tenho certeza de que há uma razão para os desenvolvedores Java criarem a classe Scanner, mas como é melhor do que apenas ter uma função normal para fazer o trabalho?

Encontrei este link que pode parecer fazer a mesma pergunta, mas as respostas são apenas sobre

"você precisa criar um objeto porque não é estático" ...

Meu palpite é: como o Java é orientado a objetos, eles decidiram colocar todos os métodos de entrada em uma classe. Eles não fizeram métodos estáticos para que você possa ter todo tipo de fontes diferentes (entrada do teclado, entrada do arquivo ...) em diferentes objetos?

Gostaria que alguém pudesse editar a pergunta para torná-la mais clara!

Pablito
fonte

Respostas:

34

A resposta é "porque um scanner possui estado".

Observando o código do java.util.Scanner , você verá vários campos particulares, como um buffer e suas informações associadas, um Matcher, um Pattern, uma fonte de entrada, informações sobre se a fonte está fechada ou não, o tipo da última coisa correspondida, informações sobre se a última coisa foi uma correspondência válida ou não, a raiz usada para números, o local (informações sobre se você está usando .ou ,como separador de milhares) e seu próprio cache LRU para padrões usados ​​recentemente , as informações sobre a última exceção encontrada, algumas informações sobre a análise de números, algumas informações sobre a análise de booleanos, bastante mais informações sobre a análise de números inteiros ... e acho que é isso.

Como você pode ver, é um bloco de texto bastante grande lá. Esse é o estado do scanner. Para transformar o Scanner em uma classe estática, esse estado precisaria ser armazenado em outro lugar. A maneira C de fazê-lo realmente não tem tanto estado com isso. Você tem um fscanf. O FILE mantém algum estado sobre a posição em que está (mas isso precisa ser passado para cada chamada de fscanf). Se houve um erro, é necessário processá-lo (e então você começa a escrever um código parecido com este ) - e isso não informa informações como "Eu estava esperando um número inteiro, mas encontrei uma string".

Quando se olha o scanner teoricamente estático - todo o estado é mantido fora da classe, não é encapsulado dentro da classe. Outros bits de código podem mexer com essas variáveis. Quando outro código pode mexer com o estado da classe, fica muito difícil argumentar sobre o que a classe fará em qualquer situação.

Talvez você possa escrever algo como ScannerState { Locale loc; ... }e ter um código que resulte em:

ScannerState state = new ScannerState(a whole lot of arguments);
int foo = Scanner.nextInt(state);

Porém, isso é muito mais complicado do que ter o estado encapsulado em um objeto Scanner em primeiro lugar (e não precisar passar no estado).

Por fim, o Scanner implementa a interface, o Iterator<String>que significa que é possível usá-lo em códigos como:

Scanner in = new Scanner(someFile);
whie(in.hasNext()) { ... }

Sem conseguir obter uma instância da classe Scanner, esse tipo de estrutura se torna mais complicado dentro de uma linguagem orientada a objetos.

Comunidade
fonte
1
Tudo o que você escreveu é absolutamente verdadeiro, embora o InputStream também tenha estado, não apenas o Scanner. Se a entrada vier do console, como em C, você não precisará passar nenhum parâmetro para começar a receber a entrada. Suponho que isso foi feito desta forma para ser coerente com a forma como outros fluxos são feitas, que não exigem Estado.
Neil
@Neil InputStream equivale ao FILE*(estado posição) em C.
roquete aberração
1
O scanner implementa Iterator- não Iterable. É impossível usar o Scanner no loop for avançado.
precisa saber é o seguinte
@ratchetfreak Precisamente. É o que "state" FileInputStreams deve ter, mas não se aplica à entrada do console, pois já está tecnicamente aberto.
Neil
1
@turbanoff Obrigado por me ligar nisso. Eu corrigi isso.
7

resposta curta: você não. Você pode obter a entrada do usuário sem usar uma instância do Scanner.
Por exemplo: https://docs.oracle.com/javase/tutorial/essential/io/cl.html ou
http://alvinalexander.com/blog/post/java/java-source-code-read-command-line -entrada

jwenting
fonte
String orgName = (new BufferedReader(new InputStreamReader(System.in))).readLine();Isso é terrivelmente complicado em comparação ao uso de Scannerae também cria novas instâncias de não um, mas dois objetos apenas para descartá-los imediatamente.
Philipp
2
@ Philipp, 1) É complicado, mas certamente é uma alternativa, e 2) se você está descartando as instâncias imediatamente, está fazendo algo errado (ou você realmente só precisa ler uma linha do console).
Arturo Torres Sánchez
Você não precisa do Scanner para ler a entrada. Você também não precisa de um InputStreamReader e não precisa de um BufferedReader. Você pode trabalhar com o fluxo "bruto" em System.in, assim como em C. O scanner é simplesmente uma maneira muito confortável de consumir esse fluxo.
Traubenfuchs