5

更新:コードSSCCEの維持に関するアドバイスをありがとう。私が言ったように、これは私がここに投稿するのは初めてです。次回ここに投稿する前に、コードが十分にトリミングされていることを確認するために、次回は間違いなく時間をかけます。


ですから、私はコンピュータサイエンスの授業用のプログラムを書いていますが、理解できない奇妙な問題を抱えています。try / catchステートメントを使用して、プログラム全体をファウルして終了する前に無効なデータ型の入力を停止することで、プログラムを堅牢にしようとしましたが、機能していないようです。無効なデータ型が入力されると、プログラムはJavaの標準エラーメッセージをウィンドウに表示せずに終了します。これがなぜであるかはわかりませんが、try/catchステートメントを誤って使用していると思います。これが私のプログラムの2つのクラスです。

/* The core class for the finance calculations to be done in the FinanceApp class. */

public class FinanceCore{
  // Instance variables
  int numYears;
  double principal;
  double interestRate;
  double balance;

  public FinanceCore(){
    numYears = 0;
    principal = 0;
    interestRate = 0;
    balance = 0;
  }

  // Mutator methods that return boolean values depending on whether the input was valid or not
  public boolean setYears(int y){
    if(y >= 0){
      numYears = y;
      return true;
    }
    else return false;
  }

  public boolean setPrincipal(double p){
    if(p >= 0){
      principal = p;
      balance = principal;
      return true;
    }
    else return false;
  }

  public boolean setInterestRate(double ir){
    if(ir >= 0 && ir <= 1){
      interestRate = ir;
      return true;
    }
    else return false;
  }

  // Two accessors
  public int getYears(){
    return numYears;
  }

  public double getPrincipal(){
    return principal;
  }

  // This method calculates and returns the balance at the end of each year
  public double plusYear(){
    balance = balance*(1+interestRate);
    return balance;
  }
}

/* This program recieves three pieces of data (interest rate, principal amount, number of years) and generates an output
* table that shows how much money will be in a fund with the given parameters at the end of every year. */

import java.util.Scanner;

public class FinanceApp{

  public static void main(String[]args){
    // First, we will declare our global variables, and set them to default values
    Scanner reader = new Scanner(System.in);
    FinanceCore account = new FinanceCore();
    int menuItem = 0;

    // Now, we'll greet the user (because we're friendly like that)
    System.out.println("Welcome! Please select a menu option below.");

    while(true){
      /* Now, our first user interface: a menu system that displays four options to the user arranged in
       * columns for aesthetic effect. This is accomplished using the printf method.
       */

      System.out.printf("%n%-20s%-20s%n%-20s%-20s%n%-20s%n",
        "Set Principal[1]","Set Interest Rate[2]","Set Timespan[3]","Calculate[4]","Quit[5]");

      System.out.print(": ");

      // Now we get the user input until it is valid, and catch and errors in input type
      try {
        menuItem = reader.nextInt(); 
      }
      catch(Exception e){
        reader.nextLine(); // Clear the input stream to avoid an infinite loop
        System.out.println("Please a valid number 1-5.");
      }

      // The code for setting the principal amount
      if(menuItem == 1){
      while(true){
        System.out.print("Please enter the principal investment amount: ");

        try{
          if(account.setPrincipal(reader.nextDouble()));
          break;
        }
        catch(Exception e){
          reader.nextLine(); // Clear the input stream to avoid an infinite loop
          System.out.println("Please enter a valid dollar amount.");
        }
      }
    }
    // The code for setting the interest rate
    else if(menuItem == 2){
      while(true){
        System.out.print("Please enter the quarterly interest rate: ");
        try{
          if(account.setInterestRate(reader.nextDouble()));
          break;
         }
         catch(Exception e){
           reader.nextLine(); // Clear the input stream to avoid an infinite loop
           System.out.println("Please enter a valid decimal number between 0 and 1 (inclusive).");
         }
       }
     }

     // The code for setting the number of years
     else if(menuItem == 3){
       while(true){
         System.out.print("Please enter the number of years the account will exist: ");
         try{
           if(account.setYears(reader.nextInt()));
           break;
         }
         catch(Exception e){
           reader.nextLine(); // Clear the input stream to avoid an infinite loop
           System.out.println("Please enter a valid integer value.");
         }
       }
     }

     // This part actually executes the calculation
     else if(menuItem == 4){
       System.out.printf("%-10s%-10s%n%-10d%-10.2f%n","YEAR","BALANCE",0,account.getPrincipal());
       int count = 1;
       for(int c = account.getYears(); c > 0; c--){
         System.out.printf("%-10d%-10.2f%n",count,account.plusYear());
         count++;
       }
     }

     // If the user enters any other number, the program quits
     else
       break;
     }
   }
 }

このプログラムには、修正できないと思われる永続的な問題が1つあることに注意してください。何らかの理由で、ユーザーがメニュー選択プロンプトで無効なデータ型を入力するたびに、プログラムは終了します(ただし、エラーはスローされません)。

4

4 に答える 4

3

try-catchブロックを使用すると、基本的に、エラーメッセージの表示を処理することをコンパイラに通知します。組み込みのメッセージは表示されません。代わりに、catchステートメントに含めるエラープロンプトが表示されます。

プログラムを実行すると、エラーメッセージが表示されますが、組み込みのJavaエラーメッセージは表示されません。これがどうあるべきかです。実際には、エラーがスローされていますが、エラーをキャッチしているため、Javaはコンソールにデフォルトのメッセージを表示しません。

プログラム終了時のコメントについて:

ユーザーがメニュープロンプトで間違ったデータ型を入力した場合に何が起こっているかを確認します。menuItemまだゼロです。したがって、すべてのifステートメントはfalseと評価されます。したがって、elseステートメントが実行され、プログラムが終了します。

于 2012-12-01T03:49:36.703 に答える
3

他の回答は、期待する出力が得られない理由を説明しています。また、あなたが犯しているプログラミングの重要な間違いをいくつか紹介したいと思います。

1)そのように捕まえないでくださいException

キャッチすると、コードによってスローされるException可能性のあるすべてのサブタイプをキャッチします。Exceptionあなたの場合、明らかにスローされることを期待していますが、メソッドはまたはなどの他の例外をスローすることもできます。そして、バグを示すような他の可能性があります。InputMismatchExceptionnextXxxNoSuchElementExceptionIllegalStateExceptionNullPointerException

予期している例外を明示的にキャッチして処理し、他の例外はより一般的な予期しない例外処理のために残しておく必要があります。

Exception2)エラーメッセージを印刷してください

実際のエラーの詳細が表示されます。例えば

  try {
    menuItem = reader.nextInt(); 
  }
  catch(InputMismatchException e){
    reader.nextLine(); // Clear the input stream to avoid an infinite loop
    System.out.println(e.getMessage());
    System.out.println("Please a valid number 1-5.");
  }

実際、例外は予期しないものです。例外のスタックトレースを印刷またはログに記録して、ユーザー(またはユーザーからのエラーレポートを処理する必要がある人)が実際に何が起こったかを把握できるようにすることをお勧めします。

3)セッターの検証が失敗した場合、例外をスローします。

あなたのセッターはこの種のことをします:

public boolean setInterestRate(double ir){
    if(ir >= 0 && ir <= 1){
        interestRate = ir;
        return true;
    }
    else return false;
}

問題は3つあります。

  • セッターは通常何も返しません。これは通常のイディオムではありません。
  • メソッドの呼び出し元がセッターがfalseを返したことを確認しない場合、集合演算が行われなかったことに気付くことはありません。
  • 設定操作が失敗した理由は何もわかりません。

このように書いてください:

public boolean setInterestRate(double ir){
    if(ir >= 0 && ir <= 1){
        interestRate = ir;
    }
    else {
        throw new IllegalArgumentException(
            "Interest rate not between 0 and 1 (" + ir + ")");
    }
}
于 2012-12-01T05:10:52.607 に答える
2

無効なメニュー項目が入力された場合、menuItem = 0が取得されます。これは、ifラダーの一番下にあり、最後のブレークに到達します。

于 2012-12-01T03:46:37.610 に答える
2

次のように、catchブロックの最後のステートメントの後に続行してください。

catch(Exception e){
reader.nextLine(); // Clear the input stream to avoid an infinite loop
System.out.println("Please a valid number 1-5.");
continue;
}

進行中のプログラムを停止する例外をキャッチした後、プログラムの続行を許可するためです。

お役に立てれば。

于 2012-12-01T03:47:00.697 に答える