首頁  >  文章  >  Java  >  練習 - 使用終端模擬銀行帳戶

練習 - 使用終端模擬銀行帳戶

PHPz
PHPz原創
2024-08-12 22:43:49312瀏覽

稍微脫離理論,訓練營的下一步是練習(他們稱之為專案挑戰)。我認為包含一個實用的部分來鞏固到目前為止所涵蓋的內容會很有趣。

要求建立一個模擬銀行單一帳戶的項目,包含分行號碼帳號客戶姓名平衡。這些資料必須來自終端,最後必須顯示一則訊息,說明帳戶已成功建立並顯示輸入的資料。原始描述可以在這裡查看。

嗯,看起來很簡單。但在我收到的任何任務中,我真正喜歡做的一件事是將其分解為非常短的步驟,以便我有一個清晰的路徑可以遵循。我這樣做也是因為當我在腦海中繪製流程時,我可以理解它是否符合所要求的內容,如果我認為它不起作用,我可以快速改變行動方針。

Exercício - Simulando Uma Conta Bancária Através Do Terminal

因此,要遵循的步驟如下:

  1. 建立一個類別來「容納」終端機中接收的資料和帳戶建立方法;
  2. 向使用者詢問數據,讀取終端輸入的資訊並將其儲存在變數中;
  3. 向使用者顯示確認訊息,將變數組織成可讀的字串。

看起來並不複雜。從步驟 1 開始,我們有以下內容:

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
    }
}

儘管到目前為止,課程中還沒有深入討論訪問修飾符,但我選擇將所有字段保留為私有,想像在銀行系統中,分行、帳戶、持有人和餘額數據必須得到很好的保護,並且只有類別本身應該可以存取它們。

此外,createAccount 方法不應該傳回任何內容,而只是在控制台中顯示一則訊息,因此它的傳回值為 void。
Java 中一些令我惱火的事情就是從這個方法開始的。用於捕獲使用者輸入的任何類型資訊的 Scanner 類別沒有使用通用方法來捕獲使用者輸入的任何類型的信息,而是為每種原始類型提供特定方法。換句話說,對於字串有 Scanner.nextLine(),對於數字有 Scanner.nextInt(),對於布林值有 Scanner.nextBoolean...

Exercício - Simulando Uma Conta Bancária Através Do Terminal

相較之下,在 C# 中,我們有一個標準輸入方法,它總是傳回一個 String,然後它的類型改變:

String input = Console.ReadLine();
int.TryParse(input, out number)
Console.WriteLine(number) //completamente válido

我還需要寫一點嗎?他有。但至少我不需要記住所有方法的語法,只需記住一個並轉換為我接下來想要的類型。更加直觀。
但讓我們繼續吧,要解決這個問題還有很長的路要走。然後,下一步是要求使用者輸入客戶資料進行註冊。

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 方法中實例化這個類,看看會發生什麼。

Main.java

public class Main {  
    public static void main(String[] args) {  
        TerminalAccount account = new TerminalAccount();  
        account.createAccount();  
    }  
}

Exercício - Simulando Uma Conta Bancária Através Do Terminal

牛?為什麼帳號輸入被忽略並且演算法已經詢問了客戶的姓名?
閱讀 Scanner 類別的文檔,它解釋說它使用某種類型的字元作為分隔符號將輸入分解為標記,以知道在哪裡停止。對於 .next() 和 .hasNext() 方法(及其變體,例如 .nextInt() 和 .hasNextInt()),分隔符號是全域空格 (s+),例如空格、製表符和換行符。

此方法的作用是取得分隔符號前面的標記,將其轉換為指定的類型並傳回該值。其餘部分保留在輸入緩衝區中。
好的,到目前為止還好。問題在於,用於捕獲字串 的 .nextLine() 方法消耗了 換行符 (n),而不是丟棄它。然後,當在另一個丟棄的檔案後面使用時,它會讀取剩餘的內容並立即結束其操作,繼續執行下一行程式碼。

這聽起來令人困惑,確實如此。我做了一個圖表來幫助您理解這個流程的瘋狂之處:

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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.

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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:

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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.
Exercício - Simulando Uma Conta Bancária Através Do Terminal

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.

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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);  

        //...
    }  
}

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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)?

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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.

Exercício - Simulando Uma Conta Bancária Através Do Terminal

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:

Exercício - Simulando Uma Conta Bancária Através Do Terminal
Exercício - Simulando Uma Conta Bancária Através Do Terminal

Exercício - Simulando Uma Conta Bancária Através Do Terminal
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!

以上是練習 - 使用終端模擬銀行帳戶的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn