预防空指针

NullPointException - 图2

Switch 的空指针问题

switch 匹配哪些参数?

java8

  • 引用数据类型
  1. String
  2. Character
  3. Integer
  4. Short
  5. Byte
  • 基本数据类型
  1. char
  2. int
  3. short
  4. byte

switch 流程

switch(param is Object) 流程

  • 当参数是引用类型时
  • 代码

    1. public static void main(String[] args) {
    2. Integer str = null;
    3. // cost NullPointException
    4. switch (str) {
    5. case 2:
    6. System.out.println("null");
    7. break;
    8. default:
    9. System.out.println("default");
    10. }
    11. }
  • 反编译 javap -c <classFile>

  1. public class list5.NullTest {
  2. public list5.NullTest();
  3. Code:
  4. 0: aload_0
  5. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  6. 4: return
  7. public static void main(java.lang.String[]);
  8. Code:
  9. 0: aconst_null
  10. 1: astore_1
  11. 2: aload_1
  12. 3: astore_2
  13. 4: iconst_m1
  14. 5: istore_3
  15. 6: aload_2
  16. 7: invokevirtual #2 // Method java/lang/String.hashCode:()I
  17. 10: lookupswitch { // 1
  18. 3392903: 28
  19. default: 39
  20. }
  21. 28: aload_2
  22. 29: ldc #3 // String null
  23. 31: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  24. 34: ifeq 39
  25. 37: iconst_0
  26. 38: istore_3
  27. 39: iload_3
  28. 40: lookupswitch { // 1
  29. 0: 60
  30. default: 71
  31. }
  32. 60: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
  33. 63: ldc #3 // String null
  34. 65: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  35. 68: goto 79
  36. 71: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
  37. 74: ldc #7 // String default
  38. 76: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  39. 79: return
  40. }
  • 流程
  1. 先计算 switch(param)param的参数的 hashCode 比如上面的步骤7 (这一步就可能导致 NullPointException )
  2. lookupswitch有各个 case 值的 hashcode (步骤10
  3. 然后判断判断这个 paramhashcode 的范围
    1. may use binary search
  4. 确定匹配哪个 case 后,跳转对应的代码块
  5. 再判断对象是否相等 (步骤31, 34
  6. 再执行代码块的真正逻辑

switch(param extends Object) 流程

  • 代码

    1. public static void main(String[] args) {
    2. int str = 3;
    3. switch (str) {
    4. case 3:
    5. System.out.println("null");
    6. break;
    7. default:
    8. System.out.println("default");
    9. }
    10. }
  • 反编译 ```shell public class list5.NullTest { public list5.NullTest(); Code:

    1. 0: aload_0
    2. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
    3. 4: return

    public static void main(java.lang.String[]); Code:

    1. 0: iconst_3
    2. 1: istore_1
    3. 2: iload_1
    4. 3: lookupswitch { // 1
    5. 3: 20
    6. default: 31
    7. }
    8. 20: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
    9. 23: ldc #3 // String null
    10. 25: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    11. 28: goto 39
    12. 31: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
    13. 34: ldc #5 // String default
    14. 36: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    15. 39: return

    }

```

  • 流程(比起上面的对象比较,少了hashcode()equals() 判断)
  1. lookupswitch有各个 case 值的 value (步骤3
  2. 然后判断判断这个 param 的 的范围
    1. may use binary search
  3. 确定匹配哪个 case 后,跳转对应的代码块
  4. 执行代码块的真正逻辑