質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.23%

このコードをスマートにしてください

受付中

回答 11

投稿

  • 評価
  • クリップ 2
  • VIEW 3,772

kaito_fl

score 38

aをb乗するプログラムを作成しております。
前回の質問で回答していただいた方々のおかげでとりあえずやりたかった動作をしてくれるプログラムは完成しました。
しかしこのプログラムをもうちょっとスマートにできないかと言われ困っております。

はじめは太字の部分が下のコードのようになっており、
ラベルは好ましくないといわれ以下のようなコードになりました。

それでも首を傾げられてしまい、
フラグをつかって~みたいなことを言われました。

プログラム自体は完成していますので、あとは個人のセンスになっていくとは思うのですが、
皆様だったらこのコードをどのようにかえることができるのか気になり質問させていただきました。

簡単なコードだとは思いますが、今後の参考にさせていただきたいので、ご協力よろしくお願いいたします。

import java.util.Scanner;
public class aaa {

    public static void main(String[] args){
        loop:while(true){

            System.out.println("数値を入力して下さい。");

            Scanner scan = new Scanner(System.in);

            String a = scan.next();
            String b = scan.next();

            try{
                int j = Integer.parseInt(a);
                int k = Integer.parseInt(b);            
            } catch (Exception e) {
                System.out.println("error:半角数字で入力してください。 ");
                continue;
            }

            int answer = 1;

            for(int i = 0 ; i < Integer.valueOf(b).intValue() ; i++){
                answer = answer *Integer.valueOf(a).intValue();
            }

            System.out.print(a +"の" + b + "乗は" );
            System.out.println(answer + "です。");    
            System.out.println("計算を続けますか?[y/n]");    

            while(true){        
                String x = scan.next(); 
                if(x.equals("y")){
                    break;
                }
                else if(x.equals("n")){
                    System.out.println("計算を終了しました。");
                    System.exit(0);
                }
                else{
                    System.out.println("error:yまたはnを入力してください");    
                }
            

            }
        }

    }
}

while(true){        
                String x = scan.next(); 
                if(x.equals("y")){
                    break;
                }
                else if(x.equals("n")){
                      break loop; 
                }
                else{
                    System.out.println("error:yまたはnを入力してください");    
                }

            }
        }
        System.out.println("計算を終了しました。");
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 11

+7

Java8では以下のようなコードも書けます。参考までに。

import java.util.Scanner;
import java.util.concurrent.Callable;

public class aaa {

  static int scanInt(Scanner scan) throws Exception {
    try {
      return Integer.parseInt(scan.next());
    }
    catch(NumberFormatException e) {
      throw new Exception("error:半角数字で入力してください。");
    }
  }

  static boolean scanYesNo(Scanner scan) throws Exception {
    switch(scan.next()) {
      case "y": return true;
      case "n": return false;
      default: throw new Exception("error:yまたはnを入力してください");
    }
  }

  static boolean loopIfException(Callable<Boolean> func) {
    while(true) {
      try {
        return func.call();
      }
      catch(Exception e) {
        System.out.println(e.getMessage());
      }
    }
  }

  public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    do {
      loopIfException(() -> {
        System.out.println("数値を入力して下さい。");
        int a = scanInt(scan);
        int b = scanInt(scan);
        int answer = (int)Math.pow(a, b);
        System.out.println(a + "の" + b + "乗は" + answer + "です。");
        return true;
      });
      System.out.println("計算を続けますか?[y/n]");
    }
    while(loopIfException(() -> scanYesNo(scan)));
    System.out.println("計算を終了しました。");
  }

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+4

スマートの意味するところにもよりますが、
こんな感じでどうでしょうか?

import java.util.Scanner;

public class aaa {
    public static void main(String[] args){
        try(Scanner scan = new Scanner(System.in)){
            while(true){
                try{
                    System.out.println("数値を入力して下さい。");

                    long j = Long.parseLong(scan.next());
                    long k = Long.parseLong(scan.next());

                    long answer = (long)Math.pow(j, k);

                    System.out.println(j +"の" + k + "乗は" + answer + "です。");
                    System.out.println("計算を続けますか?[y/n]");

                    boolean loop = true;
                    while(loop){
                        String x = scan.next();
                        if(x.equals("n")) {
                                System.out.println("計算を終了しました。");
                                System.exit(0);
                        }
                        else if(x.equals("y")) loop = false;
                        else System.out.println("error:yまたはnを入力してください");
                    }
                } catch (NumberFormatException e) {
                    System.out.println("error:半角数字で入力してください。 ");
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("error:予期しないエラーが発生した為、終了します。 ");
                    System.exit(0);
                }
            }
        }
    }
}


補足1
ScannerはClosableの実装クラスなので、Scannerが不要になったらClose()を呼び出す必要がある。
その為、try-with-resourcesでインスタンスを作る事で、自動的にCloseするようにしている。

try(Scanner scan = new Scanner(System.in)){


補足2
入力値を直接引数として渡して、不要な変数を作らない。
変数が多くなれば、それだけコードが冗長かつ複雑化しやすくなる。
これは不要かもしれないけど、累乗計算は結果が大きな数字になりやすい為、勝手にlongに変えました。
もし、さらに大きな数字や、より正確な計算結果が必要ならBigDecimalを使用すると良い。

long j = Long.parseLong(scan.next());
long k = Long.parseLong(scan.next());


補足3ー1
累乗を求めるメソッドは存在するので、それを使用する。
単純な計算や文字列の加工等、様々なメソッドが予め用意されているので、
先に一度はググってみると良い。

long answer = (long)Math.pow(j, k);


補足3-2
for文で回して計算する場合は、変数をうまく使いまわす。

for(int i = 0 ; i < k ; i++){
    answer *= j;
}


補足4
int等は、文字列と一緒であれば、+演算子で組み合わせるだけで、
自動的に文字列に変換される為、下記のように変数を使いまわせる。

System.out.println(j +"の" + k + "乗は" + answer + "です。");


補足5
trueで無限ループにしてbreakで抜けるでも良いし、
変数でフラグ管理しても良い。
状況によって適したものにすると良い。

boolean loop = true;
while(loop){


補足6ー1
これは可読性や好みの問題があるから、こんなやり方もある程度の認識で。
if文内の処理は、1行(1処理)だけならば、{}が無くても良い。

else if(x.equals("y")) loop = false;
else System.out.println("error:yまたはnを入力してください");


補足6-2
別なやり方としては、xがここでしか使われないのであれば、
switchに入力値を直接渡してcaseで切り分ける方法もある。
これも人によって意見が分かれるので、こんなのもある程度の認識で。

switch (scan.next()) {
    case "n" :
        System.out.println("計算を終了しました。");
        System.exit(0);
         break;
    case "y" : loop = false; break;
    default : System.out.println("error:yまたはnを入力してください");
}


Long.parseLong()に失敗した時のcatchと、
その他の例外のcatchを書き分ける事で、他の例外との差別化を図る。
あと、ループの中にあるので、continueを書かなくてもcatchを抜けるとループする。

} catch (NumberFormatException e) {
    System.out.println("error:半角数字で入力してください。 ");
} catch (Exception e) {
    e.printStackTrace();
    System.out.println("error:予期しないエラーが発生した為、終了します。 ");
    System.exit(0);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/06 00:18

    > 補足1
    STDINをあえて閉じる必要はないのでは?

    キャンセル

  • 2016/02/06 00:56

    はい、仰るとおり閉じる必要は無いです。
    あのプログラムの内容だと、意味は無いのですが、
    他の補足で紹介しているのと同じで、説明の為にあえて書いてます。
    端的に言ってしまえば、
    「Close()とtry-with-resourcesについての説明を書きたかった」
    それだけです。
    ご指摘ありがとうございます。

    キャンセル

+2

「フラグを使って〜」の部分は、最初のループを抜けるための事でしょうか。それならば、boolean型の変数を用意して、最初のwhileの条件に使用すると良いと思います。
そして現在System.exit(0)としている部分で、そのフラグを変更します。

boolean isLoop = true;
while (isLoop) {
....
  else if(x.equals("n")){ 
    System.out.println("計算を終了しました。"); 
    isLoop = false;
    break;
  }

また、Integer.parseIntによる数値チェックで受け取っている変数jとkを、下のfor文でも使用すると良いと思います。そうすれば次の様に書くことができます。

for (int i = 0; i < k; i++) {
  answer *= j

answer *= jは、元も文と同じ意味になります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

一旦Stringで取り込んでその後変換というのも合理性に欠けるので…

import java.util.Scanner; 
public class aaa {

    public static void main(String[] args){ 
        Scanner scan = new Scanner(System.in);
        boolean doing = true;  //フラグ設定
        while(doing){

            int a, b;
            try{ 
                System.out.println("数値を入力して下さい。");

                //nextInt()で入力から直接intを取得(intにできない入力なら例外発生)
                a = scan.nextInt();  
                b = scan.nextInt();             
            } catch (InputMismatchException e) { 
                System.out.println("error:半角数字で入力してください。 "); 
                continue; 
            }

            int answer = 1;

            for(int i = 0 ; i < b ; i++){ 
                answer *= a; 
            }

            System.out.println(a + "の" + b + "乗は" + answer + "です。");     
            System.out.println("計算を続けますか?[y/n]");    

            boolean wait = true;  //y/n入力待ちフラグ
            while(wait){         
                switch(scan.next()){  
                case "n": 
                    System.out.println("計算を終了しました。"); 
                    doing = false;  //"n"の時は一番外のループを抜けるようフラグ設定
                case "y":
                    wait = false;  //"n"の時も"y"の時もここを通る
                    break; 
                default:
                    System.out.println("error:yまたはnを入力してください");     
                } 

            } 
        }

    } 
}


とまあコードを頑張って修正してみましたが今ひとつスマートじゃないですね…
メソッドに切り分けたほうがスマートになりそうです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

まず、どういうコードがスマートか分からないと困りますよね。
いろいろな観点のスマートさがありますが、どのプログラムにも求められるのは分かりやすさです。

まず、プログラムにさせたいことを、コメントとして書いてみてください。
それに合わせてプログラムを書くと、今よりはスマートなプログラムになりますよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/08 10:27

    コメントはあえて書かないように指示されているため今回は省いております。
    確かにコメントがあったほうがわかりやすいですよね。
    つい普段からコメントを省いてしまうことが多いのでなるべく書き込むよう改善したいと思います。
    ご回答ありがとうございました。

    キャンセル

  • 2016/02/08 12:36

    横からですが、
    「何をするかを予め書いたコメントに合わせるようにコードを書く」のと
    「書いたコードに何をしているかのコメントを書く」のは違うと思いますよ。

    キャンセル

+2

次の観点で変更してみました。

main() にすべての処理を書かない (1つのメソッドの行数を少なくする)
計算部分を独立させる。(別の計算に切り替えをしやすくする)
Sysem.exit() は使用しない。
main() 部の ループを while(true){ ...}   から do { } while(...) にした。

import java.util.Scanner;

public class Clas01 {

    static Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        do {
            int[] nums = getNumbers();
            System.out.print(nums[0] + "の" + nums[1] + "乗は" + calc(nums[0], nums[1]) + "です。");
        } while (confirm_continue());
    }

    // a の b 乗を計算する (b は 0 以上であること)
    // TODO: 掛け算の回数を最適化する事。 例: 2 ^ 4 は {x = (2 * 2); x * x;} と 2 回の掛け算で計算が可能である。
    static int calc(int a, int b) {
        int result = 1;
        for (int i = 0; i < b; i++) {
            result *= a;
        }
        return result;
    }

    // 2 つの整数を標準入力から読み込む。
    static int[] getNumbers() {
        while (true) {
            try {
                System.out.println("数値を2つ入力して下さい。");
                String a = scan.next();
                String b = scan.next();
                int[] ans = { Integer.parseInt(a), Integer.parseInt(b) };
                return ans;
            } catch (Exception e) {
                System.out.println("error:半角数字で入力してください。 ");
            }
        }
    }

    // プログラムを続けるか終了するかを標準入力から読み込む。
    static boolean confirm_continue() {
        System.out.println("計算を続けますか?[y/n]");
        while (true) {
            String x = scan.next();
            if ("y".equals(x)) {
                return true;
            } else if ("n".equals(x)) {
                System.out.println("計算を終了しました。");
                return false;
            } else {
                System.out.println("error:yまたはnを入力してください");
            }
        }
    }

}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

指数部が整数であれば対数計算量で実現できます。参考にCで書きます(動作未検証)。ついでに再帰で書きました。

int myPow(int a, int b)
{
  int temp;
  switch(b){
    case 0: return 1;
    case 1: return a;
    default:;
  }
  temp = myPow(a, b / 2);
  return temp * temp * (b & 1 ? a : 1);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

回答ではないのですが。こういう意見もありますよという表明です。

はじめは太字の部分が下のコードのようになっており、 
ラベルは好ましくないといわれ以下のようなコードになりました。

それでも首を傾げられてしまい、 
フラグをつかって~みたいなことを言われました。

ラベルとフラグだったらラベルのほうがスマートです。状態はできるだけ少ない方が美しいのです。
なんなら「matobaaさんがそう言ってたよ」と言っていただいてもいいです。

フラグをつかって~と言っている人の、そう主張する根拠を掘り下げてみてはいかがでしょうか。

なお、System.exit はまったくもって美しくないです。状態だけじゃなく、文脈からなにからなにまで捨てるので乱暴すぎます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

>aをb乗するプログラムを作成しております。 
>それでも首を傾げられてしまい、 
>フラグをつかって~みたいなことを言われました。 
お題が不明確ですし
このコードって、
ロジックだけ実装するのか、
ロジックと、ロジックのテストコードを実装しているのか?
ユーザーインタフェースの御勉強をしているのか?
判らないコードになっていますよね?
⇒昔々のDOS時代のBASICで作ったコードの様に見えます。
何時、何処で、誰が、何を、どの様に、如何する、結果どうなった、どうしたい?
もしかして?
1.ユーザーインタフェースとロジックを分けて
2.クラス化して~~
3.Javadoc フォーマットの御勉強した?してない?
とか、言われませんでした?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

機能・処理順序・利用メソッドを変えずに行数、字数を減らしました。
べき乗計算はjava.util.Math#pow(double,double)で代替しました。
このサイトでの初投稿のテスト的なところもあるので、ミスがあったらすみません。

import java.util.*; 
class Aaa {
    public static void main(String[] args){ 
        while(true){
            Scanner scan = new Scanner(System.in);
            System.out.println("数値を入力して下さい。");

            int a, b;
            try{
                a = scan.nextInt(); 
                b = scan.nextInt(); 
            } catch (Exception e) { 
                System.err.println("error:半角数字で入力してください。 "); 
                continue; 
            }

            int answer = (int)Math.pow(a * 1.0, b * 1.0);

            String str = "";
            str += a +"の" + b + "乗は";
            str += answer + "です。\n";
            str += "計算を続けますか?[y/n]";
            System.out.println(str);    

            while(true){         
                String x = scan.next();  
                if(x.equals("y"))break;
                else if(x.equals("n")){ 
                    System.out.println("計算を終了しました。"); 
                    return;
                } 

                System.err.println("error:yまたはnを入力してください");     
            } 
        }
    } 
}


投稿者さんのコードに指摘をするなら、

  • クラス名の先頭を大文字にしていない
  • intに変換できるかどうか確かめるだけならInteger.parseInt(a);をわざわざ変数で受け取る必要がない
  • Integer.parseInt(a)でint型に変換しているのに、Integer.valueOf(a).intValue()でまたint型に変換している
  • breakで指定していたラベルが、breakを外した後なのに残っている(loop:while())

など。これらがスマートに見えない主な要因だと思います。

機能は変えていませんが、より攻めてみました。逆に見づらいかもしれませんが行数は少ないです。

import java.util.*; 
class Pow {
    public static void main(String[] args){ 
        while(true){
            Scanner scan = new Scanner(System.in);
            String str = "";
            System.out.println("数値を入力して下さい。");

            try{
                int a = scan.nextInt(), b = scan.nextInt();
                str += a +"の" + b + "乗は";
                str += (int)Math.pow(a * 1.0, b * 1.0) + "です。\n";
            } catch (Exception e) { 
                System.err.println("error:半角数字で入力してください。 "); 
                continue; 
            }

            str += "計算を続けますか?[y/n]";
            System.out.println(str);    

            while(true){         
                str = scan.next();  
                if(str.equals("y"))break;
                else if(str.equals("n")){ 
                    System.out.println("計算を終了しました。"); 
                    return;
                } 

                System.err.println("error:yまたはnを入力してください");     
            } 
        }
    } 
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

.InputMismatchException eを使うと全角で数字を入力した場合のエラーも拾うことができます。

import java.util.*;

public class Main {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       try{
           int a = sc.nextInt();
           int b = sc.nextInt();
           System.out.println(a + "の" + b + "乗は" + (int)Math.pow(a,b) + "です。");
       }
       catch(InputMismatchException e){
           System.out.println("半角で数字を入力してください。");
       }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る