【问题标题】:Question about InputMismatchException while using Scanner关于使用 Scanner 时 InputMismatchException 的问题
【发布时间】:2010-04-25 12:25:31
【问题描述】:

问题:

输入文件:客户账号,账户余额 月初,交易类型(提款,存款, 利息),交易金额

输出:账号,期初余额,期末余额, 支付的利息总额、存款总额、数量 存款、取款总额、取款次数

package sentinel;

import java.io.*;
import java.util.*;

public class Ex7 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws FileNotFoundException
 {
        int AccountNum;
        double BeginningBalance;
        double TransactionAmount;
        int TransactionType;
        double AmountDeposited=0;
        int NumberOfDeposits=0;
        double InterestPaid=0.0;
        double AmountWithdrawn=0.0;
        int NumberOfWithdrawals=0;
        boolean found= false;

        Scanner inFile = new Scanner(new FileReader("Account.in"));
        PrintWriter outFile = new PrintWriter("Account.out");

           AccountNum = inFile.nextInt();
           BeginningBalance= inFile.nextDouble();

           while (inFile.hasNext())
        {
               TransactionAmount=inFile.nextDouble();
               TransactionType=inFile.nextInt();
                outFile.printf("Account Number: %d%n", AccountNum);
                outFile.printf("Beginning Balance: $%.2f %n",BeginningBalance);
                outFile.printf("Ending Balance: $%.2f %n",BeginningBalance);
                outFile.println();
               switch (TransactionType)
            {
                   case '1': // case 1 if we have a Deposite
                BeginningBalance = BeginningBalance
                        + TransactionAmount;
                AmountDeposited = AmountDeposited
                        + TransactionAmount;
                NumberOfDeposits++;
                outFile.printf("Amount Deposited: $%.2f %n",AmountDeposited);
                outFile.printf("Number of Deposits: %d%n",NumberOfDeposits);
                outFile.println();

                break;
                   case '2':// case 2 if we have an Interest
                BeginningBalance = BeginningBalance
                        + TransactionAmount;
                InterestPaid = InterestPaid
                        + TransactionAmount;
                outFile.printf("Interest Paid: $%.2f %n",InterestPaid);
                outFile.println();

                break;

                   case '3':// case 3 if we have a Withdraw
                BeginningBalance = BeginningBalance
                        - TransactionAmount;
                AmountWithdrawn = AmountWithdrawn
                        + TransactionAmount;
                NumberOfWithdrawals++;
                outFile.printf("Amount Withdrawn: $%.2f %n",AmountWithdrawn);
                outFile.printf("Number of Withdrawals: %d%n",NumberOfWithdrawals);
                outFile.println();

                    break;

                default:
                System.out.println("Invalid transaction Tybe: " + TransactionType
                        + TransactionAmount);

               }
           }
           inFile.close();
           outFile.close();
    }
}

但是给了我这个:

Exception in thread "main" java.util.InputMismatchException
        at java.util.Scanner.throwFor(Scanner.java:840)
        at java.util.Scanner.next(Scanner.java:1461)
        at java.util.Scanner.nextInt(Scanner.java:2091)
        at java.util.Scanner.nextInt(Scanner.java:2050)
        at sentinel.Ex7.main(Ex7.java:36)
Java Result: 1

【问题讨论】:

  • 仅供参考,使用double 代表金钱是一个的想法。但是对于家庭作业,这没关系。

标签: java


【解决方案1】:

这就是我将如何进行:

  • API documentation 中查找异常的含义。
  • 想想它是如何发生的,它发生在哪一行(查看您的堆栈跟踪)。如果您不知道如何阅读堆栈跟踪,here's a tutorial
  • 如果您无法立即看到原因,请设置断点并通过调试器运行它,以便在异常发生之前“可视化”程序的当前状态。

您可能还不知道如何使用您的调试器,虽然有些人可能不同意,但我认为这永远不会太早。有一些关于如何使用调试器here 的优秀视频教程。祝你好运!

【讨论】:

    【解决方案2】:

    我想现在回答这个问题有点太晚了,但我最近偶然发现了同样的问题,我的谷歌搜索把我带到了这里。

    我认为Scanner.nextDouble() 抛出的InputMismatchException 最常见的情况是Scanner 使用的默认语言环境需要不同格式的双精度(例如,10,5,而不是10.5)。如果是这样的话,你应该使用Scanner.useLocale这样的方法

    Scanner s = new Scanner(System.in);
    s.useLocale(Locale.US);
    

    【讨论】:

      【解决方案3】:

      如果您阅读了Exception 消息,那是InputMismatchException。这很可能是由nextDouble()nextInt() 函数引起的,当它没有读取正确的类型时。确保您的数据正确对齐,并且您没有使用 readInt() 读取双精度数据。

      【讨论】:

        【解决方案4】:

        您可能希望包含Account.in 的内容以提供更多信息,但这里有一些 cmets:

        Naming conventions

        变量:除变量外,所有实例、类和类常量的大小写混合,首字母小写

        这意味着按照惯例,变量名应该是大写/小写的,例如accountNumbeginningBalancenumberOfDeposits 等。

        还应该提到的是,您放置花括号的方式非常不合常规。 learn good coding style 对您来说可能是个好主意。


        这部分也是高度不一致的:

        int TransactionType; // declared as int
        //...
        TransactionType=inFile.nextInt(); // read as int
        //...
        switch (TransactionType)
           case '1': // used as ... char? ASCII '1' = 49
        

        我 99% 确定您确实需要在 case 1:case 2:case 3: 上使用 switch


        您可能还希望在您处理交易之后打印期末余额。现在,您将始终为期初余额和期末余额打印相同的数字。

        了解 Java 具有“复合赋值”运算符可能也会使您受益,这将使您的代码更具可读性。您现在可能不需要关心确切的语义,但基本上不是这样:

                    BeginningBalance = BeginningBalance
                            + TransactionAmount;
        
                    BeginningBalance = BeginningBalance
                            - TransactionAmount;
        

        您可以改为:

        beginningBalance += transactionAmount;
        
        beginningBalance -= transactionAmount;
        

        最后,关于InputMismatchException 的最后一条评论:其他人已经向您解释了这意味着什么。我现在最好的猜测是你的问题是由这个引起的:

        输入文件:客户账号、月初账户余额、交易类型(取款、存款、利息)、交易金额

        对比:

                   TransactionAmount=inFile.nextDouble();
                   TransactionType=inFile.nextInt();
        

        我需要查看Account.in 进行确认,但我怀疑int 交易类型出现在double 交易金额之前,就像问题陈述中所说的那样。您的代码以相反的顺序读取它们。

        这会尝试将int 读取为nextDouble(),这没关系,但doublenextInt() 会抛出InputMismatchException

        【讨论】:

        • 这是我第一次学习java >>> 我不知道如何组织(Account.in)文件。我是这样做的:((((467343 10000.00 250.00 1 1200.00 2 75.00 2 375.00 3 100.00 2)))
        • @aser:看起来Account.indouble int 对应amount type,所以这个顺序没问题。不过,您肯定想在case 1: 上使用switch 而不是case '1':。我建议调试,或者使用集成的单步执行,或者只是放置大量 System.out.println 语句,例如每次从输入中读取某些内容时,将其内容打印到屏幕上。这样您就知道何时抛出异常,并希望定位问题并修复它。
        【解决方案5】:

        我不是特别喜欢这种设计,因为它违背了 Java 的优势,有点面向对象。所以我按照我认为的思路重写了程序。

        我还发现解释双打是依赖于语言环境,在我的机器上,双打(在字符串中)应该有一个逗号(12,12)而不是一个点(12.12),所以可能是你的问题。

        正如 polygenelubricants 所说,Java 中的成员和方法名称是小写的,只有类型使用大写。

        我添加了我自己的实现,不是因为您的实现不起作用,而是为了展示如何将职责委托给反映问题域的类,从而使代码更具可读性(尽管使用样板 getter 和 setter 的时间要长得多)。

        我对你的程序的实现是这样的:

        import java.io.FileNotFoundException;
        import java.io.FileReader;
        import java.io.PrintWriter;
        import java.util.Scanner;
        
        public class Ex7 {
            /**
             * One transaction record in the file Should be format "int double\n"
             * Note that interpreting a double is locale dependent, on my machine
             * I need "12,24" whereas a US locale might require "12.24"
             */
            public static class Transaction {
                double amount;
                int type; // Prefer an enum here...
        
                public void read(Scanner scanner) {
                    setAmount(scanner.nextDouble());
                    setType(scanner.nextInt());
                }
        
                public int getType() {
                    return type;
                }
        
                public void setType(int type) {
                    this.type = type;
                }
        
                public double getAmount() {
                    return amount;
                }
        
                public void setAmount(double amount) {
                    this.amount = amount;
                }
        
                @Override
                public String toString() {
                    return String.format("Transaction(type=%d, amount=%.2f)", type, amount);
                }
            }
        
            /**
             * Account information and processing Account file format: Line 1
             * "int double\n" account number start balance Line 2-... "double int\n"
             * transaction amount transaction type.
             * Type 1=deposit, 2=interest
             * 3=withdrawal
             */
            public static class Account {
                int accountNum;
                double startBalance;
                double currentBalance;
                double totalDeposited;
                double totalWithdrawn;
                double totalInterestPaid;
                int numberOfDeposits;
                int numberOfWithdrawals;
                int numberOfInterestPayments;
        
                public Account(Scanner scanner) {
                    read(scanner);
                }
        
                private void read(Scanner scanner) {
                    setAccountNum(scanner.nextInt());
                    setStartBalance(scanner.nextDouble());
                    setCurrentBalance(getStartBalance());
                }
        
                public int getAccountNum() {
                    return accountNum;
                }
        
                public void setAccountNum(int accountNum) {
                    this.accountNum = accountNum;
                }
        
                public double getStartBalance() {
                    return startBalance;
                }
        
                public void setStartBalance(double startBalance) {
                    this.startBalance = startBalance;
                }
        
                public double getCurrentBalance() {
                    return currentBalance;
                }
        
                public void setCurrentBalance(double currentBalance) {
                    this.currentBalance = currentBalance;
                }
        
                public void processTransaction(Transaction transaction) {
                    switch (transaction.getType()) {
                    case 1:
                        handleDeposit(transaction.getAmount());
                        break;
                    case 2: // Isn't this just a deposit?
                        handleInterest(transaction.getAmount());
                        break;
                    case 3:
                        handleWithdraw(transaction.getAmount());
                        break;
                    default:
                        throw new RuntimeException("Can not process transaction " + transaction + ", transaction type unknown.");
                    }
                }
        
                private void handleDeposit(double deposit) {
                    numberOfDeposits++;
                    currentBalance += deposit;
                    totalDeposited += deposit;
                }
        
                private void handleInterest(double interestPaid) {
                    numberOfInterestPayments++;
                    currentBalance += interestPaid;
                    totalInterestPaid += interestPaid;
                }
        
                private void handleWithdraw(double amountWithdrawn) {
                    numberOfWithdrawals++;
                    currentBalance -= amountWithdrawn;
                    totalWithdrawn += amountWithdrawn;
                }
        
                public String getOverview() {
                    StringBuilder stringBuilder = new StringBuilder();
                    stringBuilder.append("Total Deposited : " + totalDeposited).append("\n");
                    stringBuilder.append("Total Withdrawn : " + totalWithdrawn).append("\n");
                    stringBuilder.append("Total Interest  : " + totalInterestPaid).append("\n");
                    stringBuilder.append("Current Balance : " + currentBalance).append("\n").append("\n");
                    return stringBuilder.toString();
                }
        
            }
        
            /**
             * @param args
             *            the command line arguments
             */
            public static void main(String[] args) throws FileNotFoundException {
        
                Scanner inFile = null;
                PrintWriter outFile= null;
                try {
                    inFile = new Scanner(new FileReader("Account.in"));
                    outFile = new PrintWriter("Account.out");
        
                    Account account;
                    try {
                        account = new Account(inFile);
                    } catch (RuntimeException e) {
                        // Catch exception for error message display
                        System.err.println("Could not read account information from file. Quitting");
                        System.exit(1);
                        return; // Otherwise compiler error :)
                    }
        
                    int lineNumber = 1; // Start with 1 because first line has account info
                    while (inFile.hasNext()) {
                        Transaction transaction = new Transaction();
                        try {
                            transaction.read(inFile);
                        } catch (RuntimeException e) {
                            System.err.println("An error ocurred while processing a transaction on line " + lineNumber + ". Transaction " + transaction + " incomplete and failed");
                            throw e; // rethrow and let the stack trace shine!
                        }
                        lineNumber++;
        
                        outFile.printf("Account Number: %d%n", account.getAccountNum());
                        outFile.printf("Beginning Balance: $%.2f %n", account.getStartBalance());
                        outFile.printf("Current Balance: $%.2f %n", account.getCurrentBalance());
                        outFile.println();
        
                        account.processTransaction(transaction);
                        outFile.print(account.getOverview());
        
                    }
                } finally {
                    if (inFile != null) {
                        inFile.close(); // This can also yield an exception, but I just don't care anymore :)
                    }
                    if (outFile != null) {
                        outFile.close();
                    }
                }
            }
        }
        

        【讨论】:

        • 感谢您的努力,但必须通过 switch 和 while 和 if 循环来完成。我没有在你的解决方案中考虑很多东西。
        • @aser 没问题。我意识到这看起来有点矫枉过正。我通常使用数千行的 Java 代码,这些代码需要经过多年的维护和扩展。它强制采用不同的设计方式:)
        猜你喜欢
        • 1970-01-01
        • 2017-03-06
        • 2017-05-13
        • 1970-01-01
        • 2017-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-04
        相关资源
        最近更新 更多