Um ein wenig aus der Theorie herauszukommen, ist der nächste Schritt im Bootcamp eine Übung (die sie Projekt-Challenge nennen). Ich dachte, es wäre interessant, einen praktischen Teil aufzunehmen, um die bisher behandelten Inhalte zu festigen.
Gewünscht war die Erstellung eines Projekts, das ein einzelnes Konto in einer Bank simuliert, das Filialennummer, Kontonummer, Kundenname und Balance. Diese Daten müssen vom Terminal stammen und am Ende muss eine Meldung angezeigt werden, dass das Konto erfolgreich erstellt wurde und welche Daten eingegeben wurden. Die Originalbeschreibung finden Sie hier.
Nun, es scheint ziemlich einfach zu sein. Aber eine Sache, die ich bei jeder Aufgabe, die ich bekomme, wirklich gerne mache, ist, sie in sehr kurze Schritte zu unterteilen, damit ich einen klaren Weg habe, dem ich folgen kann. Ich mache das auch, weil ich, während ich den Ablauf in meinem Kopf zeichne, verstehen kann, ob die Frage einen Sinn ergibt, und ich die Vorgehensweise schnell ändern kann, wenn ich denke, dass sie nicht funktioniert.
Daher sind folgende Schritte zu befolgen:
TerminalAccount.java
public class TerminalAccount { // eu sei, sou muito criativo private int branch; private String account; private String clientName; private double balance; public void createAccount(){ // aqui a mágica acontece } }
Außerdem sollte die Methode „createAccount“ nichts zurückgeben, sondern lediglich eine Meldung in der Konsole anzeigen, sodass die Rückgabe ungültig ist.
Bei dieser Methode beginnen einige Dinge, die mich an Java irritieren. Anstelle einer generischen Methode, die alle Arten von Informationen erfasst, die der Benutzer eingibt, verfügt die Scanner-Klasse, die hierfür verwendet wird, über
spezifische Methoden für jeden primitiven Typ. Mit anderen Worten, es gibt Scanner.nextLine() für Strings, Scanner.nextInt() für Zahlen, Scanner.nextBoolean für boolesche Werte ...
Im Vergleich dazu haben wir in C# eine Standardeingabemethode, die immer einen String zurückgibt, dessen Typ dann geändert wird:
String input = Console.ReadLine(); int.TryParse(input, out number) Console.WriteLine(number) //completamente válido
Aber machen wir weiter, bis zur Lösung dieses Problems ist es noch ein weiter Weg. Im nächsten Schritt wird der Benutzer dann aufgefordert, Kundendaten für die Registrierung einzugeben.
TerminalAccount.java
public class TerminalAccount { private int branch; private String account; private String clientName; private double balance; public void createAccount() { Scanner sc = new Scanner(System.in); System.out.print("Por favor, insira o número da agência: "); this.branch = sc.nextInt(); System.out.print("Por favor, insira o número da conta: "); this.account = sc.nextLine(); System.out.print("Por favor, insira o nome do cliente: "); this.clientName = sc.nextLine(); System.out.print("Por favor, insira o saldo inicial: "); this.balance = sc.nextDouble(); System.out.println("Olá " + this.clientName + ", obrigado por criar uma conta em nosso banco. sua agência é " + this.branch + ", conta " + this.account + " e seu saldo " + this.balance + " já está disponível para saque."); } }
Main.java
public class Main { public static void main(String[] args) { TerminalAccount account = new TerminalAccount(); account.createAccount(); } }
Ochse? Warum wurde die Eingabe der Kontonummer ignoriert und der Algorithmus bereits nach dem Namen des Kunden gefragt?
Beim Lesen der Dokumentation zur Klasse „Scanner“ wird erklärt, dass sie die Eingabe in Token aufteilt und dabei einen Zeichentyp als Trennzeichen verwendet, um zu wissen, wo sie aufhören muss. Im Fall der Methoden .next() und .hasNext() (und deren Varianten wie .nextInt() und .hasNextInt()) ist das Trennzeichen ein globales Leerzeichen (s+) wie Leerzeichen, Tabulatoren und Zeilenumbrüche .
Okay, soweit ok. Das Problem besteht darin, dass die .nextLine()-Methode, die zum Erfassen von Zeichenfolgen
verwendet wird, das Zeilenumbruchzeichen (n) verbraucht, anstatt es zu verwerfen. Wenn es dann nach einem anderen verwendet wird, der verwirft, liest es, was zurückgeblieben ist, beendet sofort seinen Vorgang und fährt mit der nächsten Codezeile fort.
Tá, e como consertamos essa lambança? Simples: adicionando um novo Scanner.nextLine() logo depois do .nextInt() para "limpar" o que sobrou. É bonito? Não, mas resolve.
Dá pra mudar o delimitador para aceitar a quebra de linha (\n ) em vez de um whitespace comum (\s+), mas isso poderia quebrar a forma com que as informações são quebradas em tokens, então é melhor deixar pra lá.
TerminalAccount.java
public class TerminalAccount { private int branch; private String account; private String clientName; private double balance; public void createAccount() { Scanner sc = new Scanner(System.in); System.out.print("Por favor, insira o número da agência: "); this.branch = sc.nextInt(); sc.nextLine(); //... } }
Mais feio que bater na mãe.
Beleza, funcionou. Poderíamos dizer que o exercício está completo, mas vamos por um segundo imaginar que o usuário, sem querer, digitou uma letra na hora de colocar o número da agência:
Eita lasqueira.
Isso acontece porque, como já sabemos, a tipagem do Java é estática e o Scanner está esperando um número mas quando colocamos uma letra junto com um número, essa cadeia se torna uma String. O input que estava esperando um int recebeu uma String e ficou confuso tal qual uma criança que recebe meias de presente de natal.
Para remediar essa situação, podemos criar um loop simples, que informe para o usuário que a informação que ele inseriu está incorreta de acordo com as especificações do sistema e pedir que ele insira os dados novamente (de maneira correta, dessa vez). Como não sabemos quantas tentativas o usuário vai levar para inserir os dados corretamente, um while parece adequado.
public class TerminalAccount { private int branch; private String account; private String clientName; private double balance; public void createAccount() { Scanner sc = new Scanner(System.in); boolean isBranchNumberInputCorrect = false; do { try { System.out.print("Por favor, insira o número da agência: "); this.branch = sc.nextInt(); sc.nextLine(); isBranchNumberInputCorrect = true; } catch (InputMismatchException e) { System.out.println("Por favor, insira apenas números inteiros para o número da agência."); sc.nextLine(); } } while (!isBranchNumberInputCorrect); //... } }
Aqui criamos uma variável de controle chamada IsBranchNumberInputCorrect (porque, novamente, sou muito criativo quando se trata de nomes), inicializada em false. Em seguida, começamos o bloco do, uma vez que queremos que o código faça uma ação antes de verificar se o dado inserido é valido ou não e jogamos nosso input lá pra dentro.
Caso dê tudo certo, o dado inserido será armazenado no campo branch, qualquer caractere sobrando será consumido pelo Scanner.nextLine() e a nossa variável de controle será atualizada para true. Aí a condição do while vai checar se isBranchNumberInputCorrect é false. Se for, reinicia o loop no caso de sucesso, o laço é encerrado.
Agora, caso o usuário insira algo não esperado (como uma String), o método Scanner.nextInt() vai emitir um evento de erro InputMismatchException, que será capturado pelo nosso bloco catch. Uma vez lá dentro, o código vai exibir uma mensagem de erro alertando que o tipo de dado está errado e consumido qualquer caractere que tenha ficado pra trás.
A gente pode fazer a mesma coisa com o input de saldo, para garantir que o valor inserido sempre será numérico e não permitir que a aplicação quebre caso seja inserido algo como 12,56f:
public class TerminalAccount { private int branch; private String account; private String clientName; private double balance; public void createAccount() { Scanner sc = new Scanner(System.in); //... boolean isBalanceInputCorrect = false; do { try { System.out.print("Por favor, insira o saldo inicial: "); this.balance = sc.nextDouble(); sc.nextLine(); isBalanceInputCorrect = true; } catch (InputMismatchException e) { System.out.println("Por favor, insira apenas valores decimais."); sc.nextLine(); } } while (!isBalanceInputCorrect); //... } }
Poderíamos parar por aqui e dar esse exercício como encerrado, mas ainda tem um bug que requer um pouco de atenção. O que aconteceria se, em vez de delimitarmos nosso saldo com uma vírgula (,) usássemos um ponto (por exemplo, 10.56)?
Isso acontece devido ao locale, a adaptação do input à cultura do local. Aqui no Brasil, o decimal é delimitado pela vírgula, então o método não entende que essa separação com ponto é válida.
A documentação da classe Scanner nos mostra que é possível alterar a cultura para uma que atenda ou um ou outro padrão, mas não os dois ao mesmo tempo. Também é possível alterar especificamente o delimitador, para um símbolo ou para outro, mas não os dois ao mesmo tempo.
Um dos métodos para solucionar esse problema não é muito elegante, mas resolve: em vez de capturar o dado diretamente como double, vamos usar o método Scanner.nextLine() para pegar o input como uma String, trocar os pontos por vírgula e tentar trocar o tipo para double.
public class TerminalAccount { private int branch; private String account; private String clientName; private double balance; public void createAccount() { Scanner sc = new Scanner(System.in); //... boolean isBalanceInputCorrect = false; do { try { System.out.print("Por favor, insira o saldo inicial: "); String balanceString = sc.nextLine().replace(",", "."); this.balance = Double.parseDouble(balanceString); isBalanceInputCorrect = true; } catch (NumberFormatException e) { System.out.println("Por favor, insira apenas valores decimais."); } } while (!isBalanceInputCorrect); //... } }
Além da alteração do método de captura do dado, tivemos mais algumas modificações: retiramos as chamadas para o método Scanner.nextLine() que serviam apenas para consumir os caracteres remanescentes, porque nosso input já faz isso pra gente. Além disso, o tipo do erro mudou: agora não se trata de um erro de incompatibilidade de tipo (InputMismatchException), mas sim um de erro no formato do número (NumberFormatException).
Com essas alterações feitas, bora ver se tudo deu certo:
Deu tudo certo! Com isso, conseguimos dizer que o exercício está concluído (finalmente)!
O repositório desse exercício está disponível aqui caso tenha interesse de ver.
E é isso. Até o próximo módulo!
Das obige ist der detaillierte Inhalt vonÜbung – Simulation eines Bankkontos mithilfe des Terminals. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!