如何在开关中使用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,当inull时,拆箱会抛出一个NullPointerExceptionexception。

*从Java 7开始,您可以在switch语句中使用String

 switch ((i != null) ? i : DEFAULT_VALUE) { //... } 

switch(i)会抛出一个NullPointerException如果我是null ,因为它会尝试解开Integerint 。 因此, 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是否处理UNKNOWNtypes。 (注意: -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语句。

  1. 简单的if语句里面的switch:

     //if 'i' different from 'null' return 'i' else return 'DEFAULT' switch(i != null ? i : DEFAULT) { case DEFAULT: break; } 
  2. 或者如果你打开string:

      String i = null; // equal to -> value != null ? value.toString() i = String.valueOf(i); : "null"; switch(i) { case "null": break; } 
  3. 上次解决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处于单独状态。