Java switchステートメントの複数のケース


118

Javaのswitchステートメントで複数のケースを使用する方法を理解しようとしています。これが私がやろうとしていることの例です:

switch (variable)
{
    case 5..100:
        doSomething();
    break;
}

やらなければならないこと:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

これが可能であればアイデアはありますか、それとも良い代替案は何ですか?


12
整数を使用しているようですので、範囲が固定サイズであることがわかっている場合は、いつでも切り替えることができます(変数/ FIXED_SIZE_OF_RANGE){ケース0:...デフォルト:ブレーク; }
ポールレクラー

回答:


80

悲しいことに、それはJavaでは不可能です。if-elseステートメントを使用する必要があります。


1
@FunJavaCode AFAIKあなたはvb.netでそれを行うことができます。ここに例があります
バラR

1
@YuryLitvinovあなたはそれが間違っていると思う理由を拡大したいですか?
Bala R

1
私の答えは、これが正しくないことを証明しています。これはオブジェクト指向であり、if/elseif/else言語に関係なく、多くのネストされたステートメントを必要とする他の人の間でこの正確な問題に対処するための既知の受け入れられたパターンです。

1
plzはそれをチェックアウト...これらのリンクを使用してスイッチケースでOR条件を得ることが可能である: - stackoverflow.com/a/16706729/3946958
ラビンドラKushwaha

4
broその可能な使用法は、breakを使用せずに複数のcaseを書き込むことができ、caseの終わりに次のようなロジックを書くことができます:case some_value:case some_value:case some_value:you_logic_goes_here break;
anoopbryan2 2016

85

2番目のオプションは完全に問題ありません。レスポンダーがそれが不可能だと言った理由がわかりません。これは結構です、そして私はいつもこれをします:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

50
質問者はこれを「対して」行うと言いました。あなたがリストしたものが有効であることを彼は理解し、その最初にINSTEADをしようとしたのです。
ブレインマックロー

45
申し訳ありませんが、同じことを行っている95件のケースを続けてリストアップすることがどのような解決策になるかはわかりません。コードでそれを見つけた場合は、追跡して誘拐し、個人的にGLaDOSに配信します。そして、彼女が見つけることができる最悪の一連のテストを提供してくれることを願っています。
アニムソン

1
@animusonの上に、彼は60回賛成されます。私は彼が答えた正確なことをしたくなかったcozにここに来た
killjoy

これは質問に答えないため、反対票を投じます。。。ヘック、どうやら、質問はこの回答を書くために読まれていなかったようです。
iheanyi

50
public class SwitchTest {
    public static void main(String[] args){
        for(int i = 0;i<10;i++){
            switch(i){
                case 1: case 2: case 3: case 4: //First case
                    System.out.println("First case");
                    break;
                case 8: case 9: //Second case
                    System.out.println("Second case");
                    break;
                default: //Default case
                    System.out.println("Default case");
                    break;
            }
        }
    }
}

でる:

Default case
First case
First case
First case
First case
Default case
Default case
Default case
Second case
Second case

Src:http : //docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html


4
それは彼が避けたかった彼の質問の「対」の部分と同じです。
Bdoserror 2013年

2
コードのみの回答は、リンクのみの回答と同じくらい悪いです。彼らは実際にはまったく答えではありません。良い答えには、説明と推論、そしておそらくいくつかの情報源や権威が含まれています。
マーカス2013年

3
それは何もないよりはましです、何人かの人々はそれを最良の答えとして、シンプルで直接的です
D4rWiNS 14年

48

以前の回答ほどエレガントではないかもしれませんが、大きな範囲が少ないスイッチケースを実現する場合は、事前に範囲を1つのケースに結合します。

// make a switch variable so as not to change the original value
int switchVariable = variable;

//combine range 1-100 to one single case in switch
if(1 <= variable && variable <=100)
    switchVariable = 1;
switch (switchVariable) 
{ 
    case 0:
        break; 
    case 1:
        // range 1-100
        doSomething(); 
        break;
    case 101: 
        doSomethingElse(); 
        break;
    etc.
} 

11
これはお勧めしません。コードを実行すると、直感的にcase 1手段variable == 1、混乱を招き、長期的には多くの痛み。コードにコメントを入れて読みやすくする必要がある場合は、何かIMHOが間違っています。
Kraxor 14

21

過度に大きなswitchand if/else構造を置き換えるオブジェクト指向のオプションの1つはChain of Responsibility Pattern、意思決定をモデル化するためにを使用することです。

責任パターンのチェーン

一連の責任パターンにより、リクエストのソースを分離して、リクエストの潜在的に多数のハンドラのどれがアクションを実行するかを決定できます。チェーンの役割を表すクラスは、ハンドラーが要求を受け入れてアクションを実行するまで、ハンドラーのリストに沿ってソースからの要求を送信します。

ジェネリックを使用してタイプセーフでもある実装例を次に示します。

import java.util.ArrayList;
import java.util.List;

/**
* Generic enabled Object Oriented Switch/Case construct
* @param <T> type to switch on
*/
public class Switch<T extends Comparable<T>>
{
    private final List<Case<T>> cases;

    public Switch()
    {
        this.cases = new ArrayList<Case<T>>();
    }

    /**
     * Register the Cases with the Switch
     * @param c case to register
     */
    public void register(final Case<T> c) { this.cases.add(c); }

    /**
     * Run the switch logic on some input
     * @param type input to Switch on
     */
    public void evaluate(final T type)
    {
        for (final Case<T> c : this.cases)
        {
            if (c.of(type)) { break; }
        }
    }

    /**
     * Generic Case condition
     * @param <T> type to accept
     */
    public static interface Case<T extends Comparable<T>>
    {
        public boolean of(final T type);
    }

    public static abstract class AbstractCase<T extends Comparable<T>> implements Case<T>
    {
        protected final boolean breakOnCompletion;

        protected AbstractCase()
        {
            this(true);
        }

        protected AbstractCase(final boolean breakOnCompletion)
        {
            this.breakOnCompletion = breakOnCompletion;
        }
    }

    /**
     * Example of standard "equals" case condition
     * @param <T> type to accept
     */
    public static abstract class EqualsCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final T type;

        public EqualsCase(final T type)
        {
            super();
            this.type = type;
        }

        public EqualsCase(final T type, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.type = type;
        }
    }

    /**
     * Concrete example of an advanced Case conditional to match a Range of values
     * @param <T> type of input
     */
    public static abstract class InRangeCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final static int GREATER_THAN = 1;
        private final static int EQUALS = 0;
        private final static int LESS_THAN = -1;
        protected final T start;
        protected final T end;

        public InRangeCase(final T start, final T end)
        {
            this.start = start;
            this.end = end;
        }

        public InRangeCase(final T start, final T end, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.start = start;
            this.end = end;
        }

        private boolean inRange(final T type)
        {
            return (type.compareTo(this.start) == EQUALS || type.compareTo(this.start) == GREATER_THAN) &&
                    (type.compareTo(this.end) == EQUALS || type.compareTo(this.end) == LESS_THAN);
        }
    }

    /**
     * Show how to apply a Chain of Responsibility Pattern to implement a Switch/Case construct
     *
     * @param args command line arguments aren't used in this example
     */
    public static void main(final String[] args)
    {
        final Switch<Integer> integerSwitch = new Switch<Integer>();
        final Case<Integer> case1 = new EqualsCase<Integer>(1)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.type.equals(type))
                {
                    System.out.format("Case %d, break = %s\n", type, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        integerSwitch.register(case1);
        // more instances for each matching pattern, granted this will get verbose with lots of options but is just
        // and example of how to do standard "switch/case" logic with this pattern.
        integerSwitch.evaluate(0);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(2);


        final Switch<Integer> inRangeCaseSwitch = new Switch<Integer>();
        final Case<Integer> rangeCase = new InRangeCase<Integer>(5, 100)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.inRange(type))
                {
                    System.out.format("Case %s is between %s and %s, break = %s\n", type, this.start, this.end, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        inRangeCaseSwitch.register(rangeCase);
        // run some examples
        inRangeCaseSwitch.evaluate(0);
        inRangeCaseSwitch.evaluate(10);
        inRangeCaseSwitch.evaluate(200);

        // combining both types of Case implementations
        integerSwitch.register(rangeCase);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(10);

    }
}

これはほんの数分で作り上げた素早いストローマンです。より洗練された実装では、ある種の実装インスタンスにCommand Pattern注入して、CaseIoCスタイルのコールバックにすることができます。

このアプローチの良い点は、Switch / Caseステートメントがすべて副作用についてであるということです。これにより、副作用がクラスにカプセル化され、それらを管理して再利用できるようになり、関数型言語でのパターンマッチングのようになり、それは悪いことではありません。

このGistの更新または拡張機能をGithubに投稿します。


2
私は同意します。大量の変数がある場合、ケースステートメントとブロックが厄介な場合は大きくなります。多くのケースステートメントを実行している場合は、OOの原則を使用しているとは異なります。
ブレインマックロー

11

による この質問に、それは完全に可能です。

同じロジックを含むすべてのケースをまとめ、break背後に置かないでください。

switch (var) {
    case (value1):
    case (value2):
    case (value3):
        //the same logic that applies to value1, value2 and value3
        break;
    case (value4):
        //another logic
        break;
}

ので、それはだcaseなしでは、break別のにジャンプしますcaseまで、breakまたはreturn

編集:

コメントに返信して、実際には同じロジックを持つ95個の値があるが、異なるロジックを持つケースの数がはるかに少ない場合、次のようにすることができます。

switch (var) {
     case (96):
     case (97):
     case (98):
     case (99):
     case (100):
         //your logic, opposite to what you put in default.
         break;
     default: 
         //your logic for 1 to 95. we enter default if nothing above is met. 
         break;
}

より細かい制御が必要な場合if-elseは、それが選択です。


2
質問はすでにこれを解決策として提供しており、範囲内のすべての値をコーディングする必要なく範囲を指定する方法があるかどうかを尋ねます(OPでは96 caseステートメントが必要です!)。受け入れられた回答に同意します。
ボヘミアン

コメントありがとうございます。多分編集を参照してください。それはすべてシナリオに依存することに同意し、5対95はそうではないかもしれません。
WesternGun、2016年

6

基本的に:

if (variable >= 5 && variable <= 100)
{
    doSomething();
}

本当にスイッチを使用する必要がある場合は、特定の範囲でさまざまなことを行う必要があるためです。その場合は、そうです。複雑になり、パターンに従うものだけが適切に圧縮されるため、コードが乱雑になります。

切り替えの唯一の理由は、数値の切り替え値をテストするだけの場合に、変数名を入力する手間を省くためです。あなたは100のことをオンにするつもりはありません、そしてそれらはすべて同じことをするつもりはありません。これは「if」チャンクのように聞こえます。


4

//違反コード

switch (i) {
  case 1:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  case 3:  // Noncompliant; duplicates case 1's implementation
    doFirstThing();
    doSomething();
    break;
  default:
    doTheRest();
}

if (a >= 0 && a < 10) {
  doFirstThing();

  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else if (a >= 20 && a < 50) {
  doFirstThing();
  doTheThing();  // Noncompliant; duplicates first condition
}
else {
  doTheRest();
}

//準拠ソリューション

switch (i) {
  case 1:
  case 3:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  default:
    doTheRest();
}

if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) {
  doFirstThing();
  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else {
  doTheRest();
}

親指を立てるに値する実際の答え。いいね。
user1735921

3

前回のJava-12リリースから、同じケースラベルの複数の定数がプレビュー言語機能で利用可能に

実際の使用に基づいて開発者のフィードバックを誘発するJDK機能リリースで利用できます。これにより、将来のJava SEプラットフォームで永続的になる可能性があります。

それは次のようになります:

switch(variable) {
    case 1 -> doSomething();
    case 2, 3, 4 -> doSomethingElse();
};

もっと見るJEP 325:スイッチ式(プレビュー)


2

Vavrライブラリを使用してこれを処理することが可能です

import static io.vavr.API.*;
import static io.vavr.Predicates.*;

Match(variable).of(
    Case($(isIn(5, 6, ... , 100)), () -> doSomething()),
    Case($(), () -> handleCatchAllCase())
);

もちろん、すべてのケースを明示的にリストする必要があるため、これはわずかな改善です。しかし、カスタム述語を定義するのは簡単です:

public static <T extends Comparable<T>> Predicate<T> isInRange(T lower, T upper) {
    return x -> x.compareTo(lower) >= 0 && x.compareTo(upper) <= 0;
}

Match(variable).of(
    Case($(isInRange(5, 100)), () -> doSomething()),
    Case($(), () -> handleCatchAllCase())
);

Matchは式なので、Runnableメソッドを直接呼び出すのではなく、インスタンスのようなものを返します。試合後Runnable可能です。

詳細については、公式ドキュメントをご覧ください。


1

別の方法としては、以下のように使用できます。

if (variable >= 5 && variable <= 100) {
        doSomething();

    }

または次のコードも機能します

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

1

JEP 354: JDK-13のスイッチ式(プレビュー)および JEP 361: JDK-14のスイッチ式(標準)は、 switchステートメントを拡張してとして使用できるようにします

今することができます:

  • スイッチ式から変数を直接割り当てる
  • 新しい形式のスイッチラベル(case L ->)を使用:

    "case L->"スイッチラベルの右側のコードは、式、ブロック、または(便宜上)throwステートメントに制限されています。

  • カンマで区切って、ケースごとに複数の定数を使用し、
  • また、これ以上の値の区切りはありません。

    スイッチ式から値を生成するには、 break with valueステートメントを削除してyieldステートメントを優先します。

スイッチ式の例:

public class SwitchExpression {

  public static void main(String[] args) {
      int month = 9;
      int year = 2018;
      int numDays = switch (month) {
        case 1, 3, 5, 7, 8, 10, 12 -> 31;
        case 4, 6, 9, 11 -> 30;
        case 2 -> {
          if (java.time.Year.of(year).isLeap()) {
            System.out.println("Wow! It's leap year!");
            yield 29;
          } else {
            yield 28;
          }
        }
        default -> {
          System.out.println("Invalid month.");
          yield 0;
        }
      };
      System.out.println("Number of Days = " + numDays);
  }
}

0

ハードコードされた値を使用する代わりに、代わりにswitchステートメントで範囲マッピングを使用することもできます。

private static final int RANGE_5_100 = 1;
private static final int RANGE_101_1000 = 2;
private static final int RANGE_1001_10000 = 3;

public boolean handleRanges(int n) {
    int rangeCode = getRangeCode(n);
    switch (rangeCode) {
        case RANGE_5_100: // doSomething();
        case RANGE_101_1000: // doSomething();
        case RANGE_1001_10000: // doSomething();
        default: // invalid range
    }
}

private int getRangeCode(int n) {
    if (n >= 5 && n <= 100) {
        return RANGE_5_100;
    } else if (n >= 101 && n <= 1000) {
        return RANGE_101_1000;
    } else if (n >= 1001 && n <= 10000) {
        return RANGE_1001_10000;
    }

    return -1;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.