例外をスローすることを提案する人々のために:
例外をスローしても、コンパイル時エラーは発生せず、ランタイムエラーが発生します。私は例外を投げることができることを知っています、私はむしろランタイム中よりもコンパイル中に死にたいです。
まず、Eclipse 3.4を使用しています。
Enumであるモードプロパティを持つデータモデルがあります。
enum Mode {on(...), off(...), standby(...); ...}
私は現在このモデルのビューを書いており、コードを持っています
...
switch(model.getMode()) {
case on:
return getOnColor();
case off:
return getOffColor();
case standby:
return getStandbyColor();
}
...
関数の最後にデフォルトのケースとreturn xxxがないため、「このメソッドはJava.awt.Color型の結果を返す必要があります」というエラーが表示されます。 Iwant誰かが列挙型に別の型を追加した場合(シャットダウンなど)のコンパイルエラーなので、 AssertionErrorをスローするデフォルトのケース。これは修正されたモードでコンパイルされ、実行時までエラーとして認識されないためです。
私の質問はこれです:
EclipseBuilder(およびjavac)は、このスイッチがすべての可能性をカバーしている(またはカバーしている)ことを認識せず、戻り値の型が必要であるという警告を停止します。 Modeにメソッドを追加せずに、必要なことを実行できる方法はありますか?
それに失敗すると、Enumの可能な値のすべてをカバーしていないswitchステートメントで警告/エラーするオプションがありますか?
編集:ロブ:コンパイルエラーです。 javacでコンパイルしようとしましたが、メソッドの最後の}を対象とする「missing return statement」エラーが表示されます。 Eclispeは、エラーをメソッドの先頭に配置するだけです。
常にVisitorパターンでEnumを使用できます。
enum Mode {
on {
public <E> E accept( ModeVisitor<E> visitor ) {
return visitor.visitOn();
}
},
off {
public <E> E accept( ModeVisitor<E> visitor ) {
return visitor.visitOff();
}
},
standby {
public <E> E accept( ModeVisitor<E> visitor ) {
return visitor.visitStandby();
}
}
public abstract <E> E accept( ModeVisitor<E> visitor );
public interface ModeVisitor<E> {
E visitOn();
E visitOff();
E visitStandby();
}
}
次に、次のようなものを実装します。
public final class ModeColorVisitor implements ModeVisitor<Color> {
public Color visitOn() {
return getOnColor();
}
public Color visitOff() {
return getOffColor();
}
public Color visitStandby() {
return getStandbyColor();
}
}
次のように使用します。
return model.getMode().accept( new ModeColorVisitor() );
これはもっと冗長ですが、新しい列挙型が宣言された場合、すぐにコンパイルエラーが発生します。
Eclipseで有効にする必要があります(ウィンドウ->設定)エラーレベルで「スイッチでカバーされていない列挙型定数」設定。
メソッドの最後に例外をスローしますが、デフォルトのケースを使用しないでください。
public String method(Foo foo)
switch(foo) {
case x: return "x";
case y: return "y";
}
throw new IllegalArgumentException();
}
誰かが後で新しいケースを追加した場合、Eclipseは彼がケースを紛失していることを彼に知らせます。したがって、本当に正当な理由がない限り、デフォルトを使用しないでください。
なぜこのエラーが発生するのかわかりませんが、提案は次のとおりです、なぜ列挙型自体で色を定義しないのですか?その後、誤って新しい色を定義することを忘れることはできません。
例えば:
import Java.awt.Color;
public class Test {
enum Mode
{
on (Color.BLACK),
off (Color.RED),
standby (Color.GREEN);
private final Color color;
Mode (Color aColor) { color = aColor; }
Color getColor() { return color; }
}
class Model
{
private Mode mode;
public Mode getMode () { return mode; }
}
private Model model;
public Color getColor()
{
return model.getMode().getColor();
}
}
ちなみに、ここでの比較のために、コンパイラエラーを含む元のケースを示します。
import Java.awt.Color;
public class Test {
enum Mode {on, off, standby;}
class Model
{
private Mode mode;
public Mode getMode () { return mode; }
}
private Model model;
public Color getColor()
{
switch(model.getMode()) {
case on:
return Color.BLACK;
case off:
return Color.RED;
case standby:
return Color.GREEN;
}
}
}
おそらく、model.GetMode()couldがnullを返すためだと思います。
あなたの問題は、あなたの列挙型がロックダウンされていることを示すインジケータとしてswitchステートメントを使用しようとしていることです。
実際には、 'switch'ステートメントとJavaコンパイラは、enumで他のオプションを許可したくないことを認識できません。enumで3つのオプションのみが必要なという事実は完全にswitch文の設計とは別に、他の人が指摘しているように、常にデフォルトの文を使用する必要があります(未処理のシナリオであるため、例外をスローする必要があります)。
誰もが触れないように、enumにコメントを自由に振りかける必要があります。また、認識できない場合にエラーをスローするようにswitchステートメントを修正する必要があります。そのようにして、すべてのベースをカバーしました。
[〜#〜] edit [〜#〜]
コンパイラエラーをスローする問題について。それは厳密には意味がありません。 3つのオプションを持つ列挙型と、3つのオプションを持つスイッチがあります。誰かが列挙に値を追加した場合、コンパイラエラーをスローする必要があります。列挙型のサイズは任意であるため、誰かが変更した場合にコンパイラエラーをスローしても意味がありません。さらに、まったく異なるクラスにあるswitchステートメントに基づいて列挙のサイズを定義しています。
EnumとSwitchの内部動作は完全に独立しているため、切り離されたままにしておく必要があります。
このための良い方法は、デフォルトのケースを追加してエラー値を返すか、例外をスローし、jUnitで自動テストを使用することです。次に例を示します。
@Test
public void testEnum() {
for(Mode m : Mode.values() {
m.foobar(); // The switch is separated to a method
// If you want to check the return value, do it (or if there's an exception in the
// default part, that's enough)
}
}
自動化されたテストを取得すると、foobarがすべての列挙に対して定義されていることに注意します。
例外をスローするデフォルトのケースを作成します。
throw new RuntimeExeption("this code should never be hit unless someone updated the enum")
...それは、Eclipseが文句を言う理由をほぼ説明しています。今日のスイッチはすべての列挙型のケースをカバーするかもしれませんが、誰かがケースを追加し、明日は再コンパイルできません。
なぜEclipseBuilderは、このスイッチがすべての可能性をカバーしている(またはカバーしているのか?)ことを認識せず、戻り値の型が必要であるという警告を停止します。 Modeにメソッドを追加せずに、必要なことを実行できる方法はありますか?
Eclipseの問題ではなく、コンパイラjavac
です。 javac
が見るのは、nothingが一致する場合に戻り値がないことです(yoがすべてに一致していることを知っているという事実ケースは無関係です)。デフォルトの場合はsomethingを返す必要があります(または例外をスローします)。
個人的には、ある種の例外を投げるだけです。
私はコメントできないので...
常に、常に、常にデフォルトのケースがあります。それがどれほど「頻繁に」ヒットするかに驚かれることでしょう(Javaですが、それでも)。
そうは言っても、私の場合にのみオン/オフのみを処理したい場合はどうでしょう。 javacによるセマンティック処理は、それを問題としてフラグを立てます。
最近(この回答は元の質問の数年後に書かれています)、Eclipseではウィンドウ->設定-> Java->コンパイラ->エラー/警告->潜在的なプログラミングの問題:
不完全なスイッチケース
デフォルトのケースが存在する場合でも信号を送る