javaのswitch,case文についての質問です。
case文の数を動的に決める方法はありますか?
私が実現したいのは、プログラム内で値が決まる変数numがあり、numの値の分のcase文を用意する。ということです。以下に実現したいプログラムのイメージを示します。
java
1int num = getNum(); 2 3switch (式){ 4 case 値1: 5 ... 6 break; 7 case 値2: 8 ... 9 break; 10... 11 12 case 値num: 13 ... 14 break; 15}
どなたか詳しい方、ご教示いただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
java switch文 case文を動的に増やす方法
Javaの文法上、case
文の値は定数値と決まっていることもあり、case
の部分を動的に増減することはできません。これは最新のJavaSE 16の言語仕様でも同様です。
Java SE16/Java Language and Virtual Machine Specification/Java SE16 - Oracle
の 14.11.1. Switch Blocks をご覧ください。
したがって、ご質問内容「case文の数を動的に決める方法はありますか?」を言葉どおり、そのままに受け止めると、「方法はありません。」となります。しかしながら他の方々の回答でも示されているように、代替の方法はあります。この回答ではHashMap
とConsumer
インターフェースを使い、{値: その値に対応する処理}
を動的に追加する方法をサンプルコードとしてご紹介します。このハッシュマップをswitch
~case
のdefault
部分で利用すれば、方法の良し悪しはさて置き、技術的にはやりたいことを実現することができるという例示です。
先に簡単に説明しておくと、Consumer (java.util.function.Consumer)とはあらかじめ用意された関数インターフェースのひとつで、指定した型の引数を1つだけ持ち、accept
と言うメソッドを実行できます。``accept`メソッドの実際の中身(処理内容)はプログラマーが定義します。最初は取っ付きにくいかもしれませんが、ラムダ式と共に理解すれば比較的気軽に使えるようになり、便利です。
Java
1import java.util.function.Consumer; 2import java.util.HashMap; 3 4public class Main { 5 6 private int field1 = 0; 7 8 private int method1() { 9 return 123; 10 } 11 12 private void run() { 13 HashMap<Integer, Consumer<Integer>> cases = new HashMap<>(); 14 15 Consumer<Integer> c1 = new Consumer<Integer>() { 16 @Override 17 public void accept(Integer v) { 18 System.out.println("動的に追加した" + v + "の処理"); 19 field1 = 2; 20 System.out.println("=== インスタンスフィールドを操作: " + field1); 21 System.out.println("=== インスタンスメソッドも呼べる: " + method1()); 22 } 23 }; 24 cases.put(3, c1); 25 26 // ラムダ式色々 27 Consumer<Integer> c2 = v -> System.out.println("動的に追加した" + v + "の処理"); 28 cases.put(4, c2); 29 cases.put(5, (v) -> System.out.println("動的に追加した" + v + "の処理")); 30 31 // ラムダ式であれば、(比較的自由に)メソッド内の変数も使える。 32 int v2 = 12345; 33 cases.put(6, (v) -> { 34 int v3 = v2 + 3; 35 System.out.println("動的に追加した" + v + "の処理 変数v3=" + v3); 36 }); 37 38 // case 0~7を実行してみる。 39 for (int num = 0; num <= 7; num++) { 40 switch (num) { 41 case 1: 42 System.out.println("組み込みのcase 1"); 43 break; 44 45 case 2: 46 System.out.println("組み込みのcase 2"); 47 break; 48 49 default: 50 // numに合致するものがあれば、accept()を呼び出し、処理を実行。 51 Consumer<Integer> c = cases.get(Integer.valueOf(num)); 52 if (c != null) { 53 c.accept(num); 54 } else { 55 System.out.println("!!! " + num + "の処理は存在しません。"); 56 } 57 break; 58 } 59 } 60 } 61 62 public static void main(String[] args) { 63 Main obj = new Main(); 64 obj.run(); 65 } 66}
これを実行すると以下のようになります。case 3~6
相当の処理が実行されているのが分かります。
CMD
1C>java Main.java 2!!! 0の処理は存在しません。 3組み込みのcase 1 4組み込みのcase 2 5動的に追加した3の処理 6=== インスタンスフィールドを操作: 2 7=== インスタンスメソッドも呼べる: 123 8動的に追加した4の処理 9動的に追加した5の処理 10動的に追加した6の処理 変数v3=12348 11!!! 7の処理は存在しません。 12 13C>
Windows 10上で、Javaのバージョンは11( "11.0.9" 2020-10-20 LTS)で実行しました。コード自体はJava 8でも動きます。
投稿2021/03/30 18:18
総合スコア9254
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こうするしかないですね、ということでは?
java
1int num = getNum(); 2 3switch (式) { 4case 1: 5 System.out.println("組み込みのcase 1"); 6 break; 7case 2: 8 System.out.println("組み込みのcase 2"); 9 break; 10default: 11 if (式 == num) { 12 // 上記定数のどれにも一致せず、かつ、getNum()の値と一致した場合の処理 13 } 14 break; 15}
投稿2021/03/31 01:24
総合スコア496
0
いろんな方法が考えられます。
ただし、「条件次第」です。
とある条件下ではこれがいいけど、とある条件下では使えない……とか制限が強すぎる……のように場合によります。
一応、方向性のために書いておきます。
私がぱっと思いつく方法では、
方法1: 単純に分割する
たとえば、質問でいうgetNum関数……いやメソッドか。それみたいにする。
ただし、bool check(...) のような感じにしておく。(メソッド名は適当だが)
それで、
Java
1if( !check1( a ) ){ // check1 がだめなら 2 if( !check2( a ) ){ // check2でもダメなら 3 ... 4 } 5}
のようにする。
ただしコード例から見てもインデントが多くなるし、可読性も低い。
なので非推奨。
(もしかしたらやり方次第かもしれないが)
方法2: オブジェクト指向風でやる。
オブジェクト指向(以下 OOP) は、『データ(= フィールド) と処理(= メソッド)をひとまとめにしたオブジェクト』なるものを中心に見る発想法です。
オブジェクトだけがデータと処理を知っているという状態です。
なので、『オブジェクトだけが知っている』と言う状態で、言い換えると、『オブジェクトに任せる』のがOOP。
※ 上記サイトはC++での説明ですが、Javaでも発想自体は同じです。
単に メソッド => メンバ関数, フィールド => メンバ変数 と言い換えていたり、
書き方が違うだけです。
この方法では、『データ(あるいは変数)が分岐で変わる場合』に使えますね。
変数 a, b, c があって、条件1 のときは a, 条件2 のときは b, 条件3 のときは c と言う風に分岐する場合です。
方法3: デザインパターンの『ChainOfresponsibilityパターン』を適用する
ただし、この場合はクラスをそれぞれで実装するので、クラスファイルが増大します。
方法4: 諦めて、そのままべた書きする
そのままです。
投稿2021/03/30 05:07
総合スコア4962
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。