如何在开关中使用null
Integer i = ... switch (i){ case null: doSomething0(); break; }
在上面的代码中,我不能在switch case语句中使用null。 我怎样才能做到这一点? 我不能使用default
因为那时我想做别的。
这在Java中的switch
语句中是不可能的。 在switch
之前检查null
:
if (i == null) { doSomething0(); } else { switch (i) { case 1: // ... break; } }
在switch
语句*中不能使用任意对象。 编译器不抱怨switch (i)
i
是一个Integer
的原因是因为Java自动将Integer
int
为一个int
。 正如已经说过的assylias,当i
为null
时,拆箱会抛出一个NullPointerException
exception。
*从Java 7开始,您可以在switch
语句中使用String
。
switch ((i != null) ? i : DEFAULT_VALUE) { //... }
switch(i)
会抛出一个NullPointerException如果我是null
,因为它会尝试解开Integer
成int
。 因此, case null
,这是违法的,永远不会到达。
你需要在switch
语句之前检查我不是null。
Java文档明确指出:
禁止使用null作为开关标签可以防止编写永远不能执行的代码。 如果开关expression式是引用types,例如装箱的基元types或枚举,则在运行时expression式计算结果为null时,将发生运行时错误。
在执行Swithch语句之前,您必须先validationnull。
if (i == null)
见交换声明
case null: // will never be executed, therefore disallowed.
鉴于:
public enum PersonType { COOL_GUY(1), JERK(2); private final int typeId; private PersonType(int typeId) { this.typeId = typeId; } public final int getTypeId() { return typeId; } public static PersonType findByTypeId(int typeId) { for (PersonType type : values()) { if (type.typeId == typeId) { return type; } } return null; } }
对我来说,这通常与数据库中的查找表保持一致(仅适用于很less更新的表)。
但是,当我尝试在switch语句中使用findByTypeId
(很可能是用户input)…
int userInput = 3; PersonType personType = PersonType.findByTypeId(userInput); switch(personType) { case COOL_GUY: // Do things only a cool guy would do. break; case JERK: // Push back. Don't enable him. break; default: // I don't know or care what to do with this mess. }
…正如其他人所说,这导致NPE @ switch(personType) {
。 我开始实施的一种解决方法(即“解决scheme”)是添加一个UNKNOWN(-1)
types。
public enum PersonType { UNKNOWN(-1), COOL_GUY(1), JERK(2); ... public static PersonType findByTypeId(int id) { ... return UNKNOWN; } }
现在,您不必执行空值检查,而是可以select是否处理UNKNOWN
types。 (注意: -1
在业务场景中是一个不太可能的标识符,但显然select一些对您的用例有意义的东西)。
你必须做一个
if (i == null) { doSomething0(); } else { switch (i) { } }
一个开关与byte,short,char和int原始数据types一起工作。 它也适用于枚举types(在枚举types中讨论),String类和几个包装特定基本types的特殊类:Character,Byte,Short和Integer(在Numbers和Strings中讨论)。
由于null没有types,并且不是任何事物的实例,所以不能用switch语句。
-
简单的if语句里面的switch:
//if 'i' different from 'null' return 'i' else return 'DEFAULT' switch(i != null ? i : DEFAULT) { case DEFAULT: break; }
-
或者如果你打开string:
String i = null; // equal to -> value != null ? value.toString() i = String.valueOf(i); : "null"; switch(i) { case "null": break; }
-
上次解决scheme没有空检查:
是!!! 我喜欢使用TRY / CATCH或THROW新exception作为IF / ELSEreplace:)
Integer i = null; try{ switch (i) {} } catch(NullPointerException npx) { // VM implementation specific message -> // Caused by: java.lang.NullPointerException: // Attempt to invoke virtual method // 'int java.lang.Integer.intValue()' on a null object reference // you need to ensure child method don't throw npx // or throws some other exception in replacement of npx if(npx.getMessage().indexOf("java.lang.Integer.intValue()")>=0) { // handle null } }
编辑 – 回复:
对于最后的解决scheme:不要用Java编写Python。 – glglgl 2月15日在14:33
…我的意思是说:在Python中,exception被认为是正常的stream量控制方法(EAFP)。 在Java中,它们被认为是他们的名字所说的:exception。 它们非常昂贵,应该小心使用。 与Python不同的是,使用TRY / CATCH或THROW new Exception,因为IF / ELSEreplace在这里不好。 – glglgl
编程例外
可以使用exception来帮助编写健壮的^ 1程序。 他们提供了一个有组织的和结构化的方法来保持健壮 没有例外的情况下,程序可能会混杂if语句来testing各种可能的错误条件。 有了例外,就可以编写一个干净的实现algorithm来处理所有的正常情况。 例外情况可以在try语句的catch子句中的其他地方处理。
当程序遇到exception情况,无法立即处理时,程序可能会抛出exception。 在某些情况下,抛出属于Java预定义类之一的exception是有意义的,例如IllegalArgumentException或IOException。 但是,如果没有充分代表exception条件的标准类,程序员可以定义一个新的exception类。 新类必须扩展标准类Throwable或它的一个子类。 一般来说,如果程序员不想要求强制性的exception处理,新的类将扩展RuntimeException(或其子类之一)。 要创build一个新的检查过的exception类,它需要强制处理,程序员可以扩展Exception的其他子类之一,或者扩展exception本身。
在这里,例如,是扩展了Exception的类,因此在使用时需要强制性的exception处理:
public class ParseError extends Exception { public ParseError(String message) { // Create a ParseError object containing // the given message as its error message. super(message); } }
^ 1正确性和鲁棒性是重要的,特别困难的一个地方是处理input数据,无论数据是由用户input,从文件读取还是通过networking接收。
甚至更好,在这里我可以给你一个Android应用程序的例子:
/** * start catcher on main thread loop * * @param context - app or any other context * @param handler - handler to post any background thread exceptions to ui thread */ public static void startCatcher(Context context, Handler handler) { /** grab app default exception handler */ Thread.UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler(); /** the following handler is used to catch exceptions thrown in background threads */ LogsExceptionHandler logsExceptionHandler = new LogsExceptionHandler(context, systemUncaughtHandler, handler); /** set to app our handler as default one */ Thread.setDefaultUncaughtExceptionHandler(logsExceptionHandler); /** loop while any exception in main looper */ while (true) try { /** start message que loop */ App.log.info("Starting crash catch Looper"); Looper.loop(); /** if we exit unexpectedly set app default handler to initial one */ Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler); /** and throw Runtime exception */ throw new RuntimeException("Main thread loop unexpectedly exited"); /** catch */ } catch (LogsExceptionHandler.BackgroundException e) { /** log and start exit hook same as for main ui caught exception */ String message = "Caught the exception in the background thread " + e.getThreadName() + ", TID: " + e.getTid() + " cause: " + e.getCause(); App.log.debug(message); logsExceptionHandler.startHook(e); } catch (Throwable e) { /** log and start exit hook for caught exception */ App.log.debug("Caught the exception in the UI thread, e: {}", e); logsExceptionHandler.startHook(e); } }
一些库试图提供替代内置的java switch
语句。 Vavr就是其中之一,他们把它推广到模式匹配。
以下是他们的文档中的一个例子:
String s = Match(i).of( Case($(1), "one"), Case($(2), "two"), Case($(), "?") );
你可以使用任何谓词,但是它们提供了许多开箱即用的方法, $(null)
是完全合法的。 我发现这是一个比替代品更优雅的解决scheme,但是这需要java8和对vavr库的依赖…
你不能。 你可以在开关中使用原始数据(int,char,short,byte)和String(String 7)。 原语不能为空。
在切换之前检查i
处于单独状态。