Как лучше в java в операторе switch использовать условное (булево) выражение?
Изобрёл такой способ:
boolean pb = false;
switch (pb ? "true" : "false") {
case "true" -> System.out.println("true");
case "false" -> System.out.println("false");
default -> System.out.println("Another");
}
Может есть ещё варианты?
Поскольку switch
не принимает булево выражение, а когда такая ситуация может возникнуть, то хочется иметь под рукой возможность решения этой проблемы.
Ответы (3 шт):
Можно создать enum
и пустить его в switch
:
enum Bool{TRUE, FALSE};
public class Main {
public static void main(String[] args) {
Bool pb = Bool.FALSE;
switch(pb) {
case TRUE ->
System.out.println("true");
case FALSE ->
System.out.println("false");
default ->
System.out.println("Another");
}
}
}
Если надо, чтобы значения Bool
принимали true
и false
, то его надо переписать следующим образом:
enum Bool{TRUE(true), FALSE(false);
private boolean value;
private Bool(boolean value) {
this.value = value;
}
public boolean getValue() {
return value;
}
};
Классический оператор switch
НЕ предназначен для обработки аргумента типа boolean
/Boolean
, для этого вполне достаточно использовать оператор if-else
.
Разумеется, можно конвертировать булевскую переменную в какой-то другой тип, допустимый в операторе switch
. В соответствии с JLS §14.11 для Java SE 21 такими типами являются char
, byte
, short
, int
или ссылочный тип (в т.ч. enum
или String
).
Примеры допустимых преобразований:
- целое число при помощи тернарного оператора:
var s = switch (b ? 1 : 0) {
case 1 -> "ИСТИНА ИСТИННАЯ";
case 0 -> "ЛЖА ПРЕВЕЛИКАЯ";
default -> "ЕРЕСЬ НЕВЕДОМАЯ";
};
- в строку при помощи
String.valueOf
var s = switch (String.valueOf(b)) {
case "true" -> "Jawohl!";
case "false" -> "Nein!";
default -> "Unbekannt!";
};
- В какой-нибудь
enum
типа того, что указан в ответе Roman C (тогда не понадобитсяdefault
для switch-выражения):
var s = switch (Bool.of(b)) {
case TRUE -> "WAHR";
case FALSE -> "FALSCH";
case NULL -> "NULL";
};
enum Bool {
TRUE,
FALSE,
NULL;
public static Bool of(Boolean b) {
return b == null ? NULL : b ? TRUE : FALSE;
}
}
В Java 21 ссылочный тип Boolean
можно применять в операторе switch
, однако соответствующие константы Boolean.FALSE
/ Boolean.TRUE
нельзя использовать напрямую, как значения из enum
, поскольку возникнет ошибка pattern or enum constant required
:
Boolean pb = true;
switch(pb) {
case Boolean.TRUE -> System.out.println("TRUE"); // pattern or enum constant required
case Boolean.FALSE -> System.out.println("FALSE");// pattern or enum constant required
default -> throw new IllegalArgumentException("Bad value " + pb);
};
То есть, если корректно определить паттерн для сопоставления с типом Boolean
, можно получить следующее вполне рабочее решение:
Boolean pb = true;
switch(pb) {
case null -> System.out.println("NULL");
case Boolean bb when bb -> System.out.println("TRUE");
case Boolean bb -> System.out.println("FALSE"); // default не нужен
};
В общем случае в оператор switch
может передаваться некая переменная общего типа Object
, и потребуется корректно обработать тип boolean
при помощи нового механизма:
static void foo(Object o) {
switch(o) {
case null -> System.out.println("null");
case Boolean b when b -> System.out.println("Yes!");
case Boolean b when !b -> System.out.println("Nope!");
default -> throw new IllegalArgumentException("bad type of " + b);
};
}
Фича сопоставления шаблонов (pattern matching) для операторов switch
была официально добавлена в Java 21 (см. Java Language Changes for Java SE 21), вышедшей в сентябре 2023 года.
Я сам люблю switch, особенно его последние фишки, но это не значит, что его нужно пихать везде где только можно и где нельзя. Не зря он не поддерживает булевые типы. Значит ответ: не возникнет таких ситуаций, не надо прикручивать switch к булевым переменным!
Другое дело когда приходит Object, тогда паттерн мэтчинг нам в помощь.
public static void main(String[] args) {
Object[] something = {true, false, "true", "false"};
for (var obj : something) {
System.out.println(
switch (obj) {
case Boolean b when b -> "bool:true";
case Boolean b when !b -> "bool:false";
case String s -> "String:" + s;
default -> "something";
});
}
}