如何在开关中使用null

时间:2022-09-23 07:47:16
Integer i = ...

switch (i){
    case null:
        doSomething0();
        break;    
    }

In the code above I cant use null in switch case statement. How can I do this differently? I can't use default because then I want to do something else.

在上面的代码中,我不能在switch case语句中使用null。我怎么能做得不一样呢?我不能使用默认,因为我想做别的。

11 个解决方案

#1


195  

This is not possible with a switch statement in Java. Check for null before the switch:

在Java中使用switch语句是不可能的。开关前检查零:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

You can't use arbitrary objects in switch statements*. The reason that the compiler doesn't complain about switch (i) where i is an Integer is because Java auto-unboxes the Integer to an int. As assylias already said, the unboxing will throw a NullPointerException when i is null.

不能在switch语句中使用任意对象*。编译器不抱怨开关(i)是整数的原因是Java自动将整数解压缩为整数。

* Since Java 7 you can use String in switch statements.

*由于Java 7,您可以在switch语句中使用String。

More about switch (including example with null variable) in Oracle Docs - Switch

更多关于转换(包括带空变量的例子)在Oracle Docs - switch

#2


48  

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

#3


28  

switch(i) will throw a NullPointerException if i is null, because it will try to unbox the Integer into an int. So case null, which happens to be illegal, would never have been reached anyway.

如果i为null, switch(i)将抛出NullPointerException,因为它将尝试将该整数解压缩为int类型,因此,无论如何都不会到达null,因为这种情况下,null是非法的。

You need to check that i is not null before the switch statement.

您需要在switch语句之前检查i是否为null。

#4


17  

Java docs clearly stated that:

Java文档明确指出:

The prohibition against using null as a switch label prevents one from writing code that can never be executed. If the switch expression is of a reference type, such as a boxed primitive type or an enum, a run-time error will occur if the expression evaluates to null at run-time.

禁止使用null作为开关标签,这将阻止人们编写永远无法执行的代码。如果开关表达式是引用类型的,例如框化的原语类型或枚举类型,如果表达式在运行时计算为null,则会出现运行时错误。

You must have to verify for null before Swithch statement execution.

必须在执行Swithch语句之前验证null。

if (i == null)

See The Switch Statement

看到Switch语句

case null: // will never be executed, therefore disallowed.

#5


10  

Given:

考虑到:

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;
    }
}

For me, this typically aligns with a look-up table in a database (for rarely-updated tables only).

对我来说,这通常与数据库中的查找表(仅适用于很少更新的表)保持一致。

However, when I try to use findByTypeId in a switch statement (from, most likely, user input)...

但是,当我尝试在switch语句中使用findByTypeId时(很可能来自用户输入)……

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.
}

...as others have stated, this results in an NPE @ switch(personType) {. One work-around (i.e., "solution") I started implementing was to add an UNKNOWN(-1) type.

…正如其他人所说,这会导致一个NPE @ switch(personType){。(即续航。我开始实现的是添加一个未知(-1)类型。

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

Now, you don't have to do null-checking where it counts and you can choose to, or not to, handle UNKNOWN types. (NOTE: -1 is an unlikely identifier in a business scenario, but obviously choose something that makes sense for your use-case).

现在,您不必对它的值进行空检查,您可以选择处理或不处理未知类型。(注意:-1在业务场景中是一个不太可能的标识符,但显然选择对您的用例有意义的东西)。

#6


5  

You have to make a

你必须做一个

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}

#7


2  

A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer (discussed in Numbers and Strings).

交换器使用字节、短、字符和int基元数据类型。它还可以使用枚举类型(枚举类型中讨论过)、字符串类和一些特殊类来包装某些基本类型:字符、字节、短和整数(在数字和字符串中讨论过)。

Since null has no type, and is not an instance of anything, it will not work with a switch statement.

因为null没有类型,而且不是任何实例,所以它不能使用switch语句。

  1. Simple if statement inside switch:

    开关内简单if语句:

    //if 'i' different from 'null' return 'i' else return 'DEFAULT'
    switch(i != null ? i : DEFAULT) {       
    
       case DEFAULT: 
    
            break;
    }
    
  2. Or if you switch on String:

    或者如果你打开字符串:

     String i = null;
     // equal to -> value != null ? value.toString() 
     i = String.valueOf(i); : "null";
     switch(i) {
     case "null": 
           break;
     }
    
  3. Last solution without null checking:

    无空检验的最后一种解决方案:

Yes!!! I love to use TRY / CATCH or THROW new Exception as IF / ELSE replacement :)

是的! ! !我喜欢用TRY / CATCH或THROW new Exception来替换:

    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
        }
    }

edit - in reply:

编辑——回答:

For your last solution: Don't program Python in Java. – glglgl Feb 15 at 14:33

对于最后一种解决方案:不要用Java编写Python。- glgl 2月15日14:33分

...I meant to say: In Python, exceptions are considered as a normal flow control method (EAFP). In Java, they are considered as what their name says: exceptions. They are quite expensive and should be used with care. Unlike in Python, use TRY / CATCH or THROW new Exception as IF / ELSE replacement is not good here. – glglgl

…我想说的是:在Python中,异常被认为是一个正常的流控制方法(EAFP)。在Java中,它们被认为是它们的名称:异常。它们很贵,应该小心使用。与Python不同,在这里使用TRY / CATCH或抛出新的异常,就好像/ ELSE替换不是很好。——glglgl

Programming with Exceptions

Exceptions can be used to help write robust ^1 programs. They provide an organized and structured approach to robustness. Without exceptions, a program can become cluttered with if statements that test for various possible error conditions. With exceptions, it becomes possible to write a clean implementation of an algorithm that will handle all the normal cases. The exceptional cases can be handled elsewhere, in a catch clause of a try statement.

例外可以用来帮助编写健壮的^ 1的程序。它们为健壮性提供了一种有组织和结构化的方法。如果没有异常,程序可能会变得混乱,如果对各种可能的错误条件进行测试的话。除了例外,可以编写一个干净的算法实现来处理所有的正常情况。在try语句的catch子句中,可以在其他地方处理异常情况。

When a program encounters an exceptional condition and has no way of handling it immediately, the program can throw an exception. In some cases, it makes sense to throw an exception belonging to one of Java's predefined classes, such as IllegalArgumentException or IOException. However, if there is no standard class that adequately represents the exceptional condition, the programmer can define a new exception class. The new class must extend the standard class Throwable or one of its subclasses. In general, if the programmer does not want to require mandatory exception handling, the new class will extend RuntimeException (or one of its subclasses). To create a new checked exception class, which does require mandatory handling, the programmer can extend one of the other subclasses of Exception or can extend Exception itself.

当程序遇到异常情况而无法立即处理时,程序可以抛出异常。在某些情况下,抛出属于Java预定义类之一的异常是有意义的,例如IllegalArgumentException或IOException。但是,如果没有标准类能够充分表示异常条件,程序员可以定义一个新的异常类。新类必须扩展标准的可抛出类或它的一个子类。通常,如果程序员不希望要求强制异常处理,那么新的类将扩展RuntimeException(或它的一个子类)。要创建一个新的检查异常类(这确实需要强制处理),程序员可以扩展异常的另一个子类,或者可以扩展异常本身。

Here, for example, is a class that extends Exception, and therefore requires mandatory exception handling when it is used:

例如,这里是一个扩展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 one place where correctness and robustness are important -- and especially difficult -- is in the processing of input data, whether that data is typed in by the user, read from a file, or received over a network.

^ 1正确性和健壮性是很重要的一个地方——特别是困难的处理输入数据,这些数据是否由用户输入,读取一个文件,通过网络或接收。

even better here i can gave you an example for android app:

更好的是,我可以给你们举一个安卓应用的例子:

/**
 * 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);
    }
}

#8


2  

Some libraries attempt to offer alternatives to the builtin java switch statement. Vavr is one of them, they generalize it to pattern matching.

一些库试图提供构建java switch语句的替代方法。Vavr就是其中之一,他们将其推广为模式匹配。

Here is an example from their documentation:

以下是他们文件中的一个例子:

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

You can use any predicate, but they offer many of them out of the box, and $(null) is perfectly legal. I find this a more elegant solution than the alternatives, but this requires java8 and a dependency on the vavr library...

您可以使用任何谓词,但是它们提供开箱即用的许多谓词,并且$(null)是完全合法的。我发现这是一个比其他方案更优雅的解决方案,但是这需要java8和对vavr库的依赖……

#9


0  

You can't. You can use primitives (int, char, short, byte) and String (Strings in java 7 only) in switch. primitives can't be null.
Check i in separate condition before switch.

你不能。您可以在switch中使用原语(int, char, short, byte)和String (java 7中的字符串)。原语不能为空。在切换前分别检查i。

#10


0  

switch (String.valueOf(value)){ case "null": default: }

switch (String.valueOf(value)){case“null”:default:}

#11


0  

You can also use String.valueOf((Object) nullableString) like

您还可以使用String.valueOf(对象)nullableString)之类

switch (String.valueOf((Object) nullableString)) {
case "someCase"
    //...
    break;
...
case "null": // or default:
    //...
        break;
}

See interesting SO Q/A: Why does String.valueOf(null) throw a NullPointerException

参见有趣的Q/A:为什么String.valueOf(null)抛出NullPointerException

#1


195  

This is not possible with a switch statement in Java. Check for null before the switch:

在Java中使用switch语句是不可能的。开关前检查零:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

You can't use arbitrary objects in switch statements*. The reason that the compiler doesn't complain about switch (i) where i is an Integer is because Java auto-unboxes the Integer to an int. As assylias already said, the unboxing will throw a NullPointerException when i is null.

不能在switch语句中使用任意对象*。编译器不抱怨开关(i)是整数的原因是Java自动将整数解压缩为整数。

* Since Java 7 you can use String in switch statements.

*由于Java 7,您可以在switch语句中使用String。

More about switch (including example with null variable) in Oracle Docs - Switch

更多关于转换(包括带空变量的例子)在Oracle Docs - switch

#2


48  

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

#3


28  

switch(i) will throw a NullPointerException if i is null, because it will try to unbox the Integer into an int. So case null, which happens to be illegal, would never have been reached anyway.

如果i为null, switch(i)将抛出NullPointerException,因为它将尝试将该整数解压缩为int类型,因此,无论如何都不会到达null,因为这种情况下,null是非法的。

You need to check that i is not null before the switch statement.

您需要在switch语句之前检查i是否为null。

#4


17  

Java docs clearly stated that:

Java文档明确指出:

The prohibition against using null as a switch label prevents one from writing code that can never be executed. If the switch expression is of a reference type, such as a boxed primitive type or an enum, a run-time error will occur if the expression evaluates to null at run-time.

禁止使用null作为开关标签,这将阻止人们编写永远无法执行的代码。如果开关表达式是引用类型的,例如框化的原语类型或枚举类型,如果表达式在运行时计算为null,则会出现运行时错误。

You must have to verify for null before Swithch statement execution.

必须在执行Swithch语句之前验证null。

if (i == null)

See The Switch Statement

看到Switch语句

case null: // will never be executed, therefore disallowed.

#5


10  

Given:

考虑到:

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;
    }
}

For me, this typically aligns with a look-up table in a database (for rarely-updated tables only).

对我来说,这通常与数据库中的查找表(仅适用于很少更新的表)保持一致。

However, when I try to use findByTypeId in a switch statement (from, most likely, user input)...

但是,当我尝试在switch语句中使用findByTypeId时(很可能来自用户输入)……

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.
}

...as others have stated, this results in an NPE @ switch(personType) {. One work-around (i.e., "solution") I started implementing was to add an UNKNOWN(-1) type.

…正如其他人所说,这会导致一个NPE @ switch(personType){。(即续航。我开始实现的是添加一个未知(-1)类型。

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

Now, you don't have to do null-checking where it counts and you can choose to, or not to, handle UNKNOWN types. (NOTE: -1 is an unlikely identifier in a business scenario, but obviously choose something that makes sense for your use-case).

现在,您不必对它的值进行空检查,您可以选择处理或不处理未知类型。(注意:-1在业务场景中是一个不太可能的标识符,但显然选择对您的用例有意义的东西)。

#6


5  

You have to make a

你必须做一个

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}

#7


2  

A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer (discussed in Numbers and Strings).

交换器使用字节、短、字符和int基元数据类型。它还可以使用枚举类型(枚举类型中讨论过)、字符串类和一些特殊类来包装某些基本类型:字符、字节、短和整数(在数字和字符串中讨论过)。

Since null has no type, and is not an instance of anything, it will not work with a switch statement.

因为null没有类型,而且不是任何实例,所以它不能使用switch语句。

  1. Simple if statement inside switch:

    开关内简单if语句:

    //if 'i' different from 'null' return 'i' else return 'DEFAULT'
    switch(i != null ? i : DEFAULT) {       
    
       case DEFAULT: 
    
            break;
    }
    
  2. Or if you switch on String:

    或者如果你打开字符串:

     String i = null;
     // equal to -> value != null ? value.toString() 
     i = String.valueOf(i); : "null";
     switch(i) {
     case "null": 
           break;
     }
    
  3. Last solution without null checking:

    无空检验的最后一种解决方案:

Yes!!! I love to use TRY / CATCH or THROW new Exception as IF / ELSE replacement :)

是的! ! !我喜欢用TRY / CATCH或THROW new Exception来替换:

    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
        }
    }

edit - in reply:

编辑——回答:

For your last solution: Don't program Python in Java. – glglgl Feb 15 at 14:33

对于最后一种解决方案:不要用Java编写Python。- glgl 2月15日14:33分

...I meant to say: In Python, exceptions are considered as a normal flow control method (EAFP). In Java, they are considered as what their name says: exceptions. They are quite expensive and should be used with care. Unlike in Python, use TRY / CATCH or THROW new Exception as IF / ELSE replacement is not good here. – glglgl

…我想说的是:在Python中,异常被认为是一个正常的流控制方法(EAFP)。在Java中,它们被认为是它们的名称:异常。它们很贵,应该小心使用。与Python不同,在这里使用TRY / CATCH或抛出新的异常,就好像/ ELSE替换不是很好。——glglgl

Programming with Exceptions

Exceptions can be used to help write robust ^1 programs. They provide an organized and structured approach to robustness. Without exceptions, a program can become cluttered with if statements that test for various possible error conditions. With exceptions, it becomes possible to write a clean implementation of an algorithm that will handle all the normal cases. The exceptional cases can be handled elsewhere, in a catch clause of a try statement.

例外可以用来帮助编写健壮的^ 1的程序。它们为健壮性提供了一种有组织和结构化的方法。如果没有异常,程序可能会变得混乱,如果对各种可能的错误条件进行测试的话。除了例外,可以编写一个干净的算法实现来处理所有的正常情况。在try语句的catch子句中,可以在其他地方处理异常情况。

When a program encounters an exceptional condition and has no way of handling it immediately, the program can throw an exception. In some cases, it makes sense to throw an exception belonging to one of Java's predefined classes, such as IllegalArgumentException or IOException. However, if there is no standard class that adequately represents the exceptional condition, the programmer can define a new exception class. The new class must extend the standard class Throwable or one of its subclasses. In general, if the programmer does not want to require mandatory exception handling, the new class will extend RuntimeException (or one of its subclasses). To create a new checked exception class, which does require mandatory handling, the programmer can extend one of the other subclasses of Exception or can extend Exception itself.

当程序遇到异常情况而无法立即处理时,程序可以抛出异常。在某些情况下,抛出属于Java预定义类之一的异常是有意义的,例如IllegalArgumentException或IOException。但是,如果没有标准类能够充分表示异常条件,程序员可以定义一个新的异常类。新类必须扩展标准的可抛出类或它的一个子类。通常,如果程序员不希望要求强制异常处理,那么新的类将扩展RuntimeException(或它的一个子类)。要创建一个新的检查异常类(这确实需要强制处理),程序员可以扩展异常的另一个子类,或者可以扩展异常本身。

Here, for example, is a class that extends Exception, and therefore requires mandatory exception handling when it is used:

例如,这里是一个扩展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 one place where correctness and robustness are important -- and especially difficult -- is in the processing of input data, whether that data is typed in by the user, read from a file, or received over a network.

^ 1正确性和健壮性是很重要的一个地方——特别是困难的处理输入数据,这些数据是否由用户输入,读取一个文件,通过网络或接收。

even better here i can gave you an example for android app:

更好的是,我可以给你们举一个安卓应用的例子:

/**
 * 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);
    }
}

#8


2  

Some libraries attempt to offer alternatives to the builtin java switch statement. Vavr is one of them, they generalize it to pattern matching.

一些库试图提供构建java switch语句的替代方法。Vavr就是其中之一,他们将其推广为模式匹配。

Here is an example from their documentation:

以下是他们文件中的一个例子:

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

You can use any predicate, but they offer many of them out of the box, and $(null) is perfectly legal. I find this a more elegant solution than the alternatives, but this requires java8 and a dependency on the vavr library...

您可以使用任何谓词,但是它们提供开箱即用的许多谓词,并且$(null)是完全合法的。我发现这是一个比其他方案更优雅的解决方案,但是这需要java8和对vavr库的依赖……

#9


0  

You can't. You can use primitives (int, char, short, byte) and String (Strings in java 7 only) in switch. primitives can't be null.
Check i in separate condition before switch.

你不能。您可以在switch中使用原语(int, char, short, byte)和String (java 7中的字符串)。原语不能为空。在切换前分别检查i。

#10


0  

switch (String.valueOf(value)){ case "null": default: }

switch (String.valueOf(value)){case“null”:default:}

#11


0  

You can also use String.valueOf((Object) nullableString) like

您还可以使用String.valueOf(对象)nullableString)之类

switch (String.valueOf((Object) nullableString)) {
case "someCase"
    //...
    break;
...
case "null": // or default:
    //...
        break;
}

See interesting SO Q/A: Why does String.valueOf(null) throw a NullPointerException

参见有趣的Q/A:为什么String.valueOf(null)抛出NullPointerException