Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the exception of null pointer in Switch

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article introduces you how to solve the Switch null pointer exception, the content is very detailed, interested friends can refer to, hope to be helpful to you.

A few days ago, I reviewed the "Alibaba Java Development Manual". There is a stipulation like this:

Out of curiosity, I'm going to study it! obsessive-compulsive disorder, no way!

Let's test it with a case first:

Public class Test {public static void main (String [] args) {String param = null; switch (param) {case "null": System.out.println ("match null string"); break; default: System.out.println ("enter default");}

Obviously, if switch passes in a null value, it will empty the pointer!

Seeing this, we can first think about the following questions:

What other types does switch support besides String?

Why does Alibaba Java Development Manual stipulate that String type parameters should be judged by null first?

Why might a null pointer exception be thrown?

Let's start to analyze the above problems.

Analysis of problems

First of all, refer to the official documentation for the description of the swtich statement.

The translation is as follows:

The expression of switch must be of type char, byte, short, int, Character, Byte, Short, Integer, String, or enum, otherwise a compilation error will occur

At the same time, the switch statement must meet the following conditions, otherwise a compilation error will occur:

Each case associated with a switch statement must be of the same type as the expression of the switch

If the switch expression is an enumerated type, the case constant must also be an enumerated type

Two case constants of the same switch are not allowed to have the same value.

The constant associated with a switch statement cannot be null

A switch statement has at most one default tag.

The translation is as follows:

When the switch statement is executed, the expression of switch is executed first. If the expression is null, NullPointerException is thrown and the execution of the entire switch statement is interrupted.

In addition, from the book Java Virtual Machine Specification, we can learn:

To sum up, it is:

1. The compiler uses tableswitch and lookupswitch instructions to generate compiled code for switch statements.

The tableswitch and lookupswitch instructions of the 2.Java virtual machine can only support conditional values of type int. If other types of values are used in swich, they must be converted to int types.

So you can see that the root cause of null pointers is that the virtual machine converts parameter expressions into int in order to implement the syntax of switch. The parameter here is null, which results in a null pointer exception.

The following is a further analysis of the contents of the official documents by disassembly.

For those who are not familiar with bytecodes, it is recommended to take a look at Meituan's article: https://tech.meituan.com/2019/09/05/java-bytecode-enhancement.html

Let's start the hard goods!

Disassemble it.

An example:

Public class Test {public static void main (String [] args) {String param = "Moon companion flying fish"; switch (param) {case "moon companion flying fish 1": System.out.println ("moon companion flying fish 1"); break; case "moon companion flying fish 2": System.out.println ("moon companion flying fish 2") Break; case "Moon Fish 3": System.out.println ("Moon Fish 3"); break; default: System.out.println ("default");}

The disassembly code gets:

Compiled from "Test.java" public class com.zhou.Test {public zhou.Test (); Code: 0: aload_0 1: invokespecial # 1 / / Method java/lang/Object. "": () V 4: return public static void main (java.lang.String []) Code: 0: ldc # 2 / / String month companion flying fish 2: astore_1 3: aload_1 4: astore_2 5: iconst_m1 6: istore_3 7: aload_2 8: invokevirtual # 3 / / Method java/lang/String.hashCode: () I 11: tableswitch {/-768121881 to-768121879-768121881: 36-768121880: 50-768121879: 64 default: 75} 36: aload_2 37: ldc # 4 / / String month with flying fish 1 39: invokevirtual # 5 / / Method java/lang/String.equals: (Ljava/lang/Object ) Z 42: ifeq 75 45: iconst_0 46: istore_3 47: goto 75 50: aload_2 51: ldc # 6 / / String Moon Flying Fish 2 53: invokevirtual # 5 / / Method java/lang/String.equals: (Ljava/lang/Object ) Z 56: ifeq 75 59: iconst_1 60: istore_3 61: goto 75 64: aload_2 65: ldc # 7 / / String Moon Flying Fish 3 67: invokevirtual # 5 / / Method java/lang/String.equals: (Ljava/lang/Object ) Z 70: ifeq 75 73: iconst_2 74: istore_3 75: iload_3 76: tableswitch {/ / 0 to 20: 104 1: 115 2: 126 default: 137} 104: getstatic # 8 / / Field java/lang/System.out:Ljava/io/PrintStream Ldc # 4 / / String Moon Flying Fish 1109: invokevirtual # 9 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V 112: goto 145115: getstatic # 8 / / Field java/lang/System.out:Ljava/io/PrintStream Ldc # 6 / / String Moon with Flying Fish 2120: invokevirtual # 9 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V 123: goto 145126: getstatic # 8 / / Field java/lang/System.out:Ljava/io/PrintStream Ldc # 7 / / String Moon with Flying Fish 3131: invokevirtual # 9 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V134: goto 145137: getstatic # 8 / / Field java/lang/System.out:Ljava/io/PrintStream 140,140: ldc # 10 / / String default 142invokevirtual # 9 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V145: return}

Let's first introduce the bytecode instructions that will be used below.

Invokevirtual: call instance method

Istore_0 stores the int type value in the local variable 0

Istore_1 stores the int type value in the local variable 1

Istore_2 stores the int type value in the local variable 2

Istore_3 stores the int type value in the local variable 3

Aload_0 loads reference type values from the local variable 0

Aload_1 loads reference type values from local variable 1

Aload_2 loads reference type values from local variable 2

Let's move on to the assembly code:

First look at the instruction with an offset of 8 and call the parameter's hashCode () function to get the hash value of the string "Moon Flying Fish".

8: invokevirtual # 3 / / Method java/lang/String.hashCode: () I

Next, let's look at the command with an offset of 11:

Tableswitch is a list of jump references, and if the value is less than the minimum value-768121881 or greater than the maximum value-768121879, jump to the default statement.

11: tableswitch {/ /-768121881 to-768121879-768121881: 36-768121880: 50-768121879: 64 default: 75}

Where-768121881 is the key and 36 is the corresponding target statement offset.

If the keys of hashCode and tableswitch are equal, then jump to the corresponding target offset. The hash value of "flying fish in the month" is not between the minimum value-768121881 and the maximum value-768121879, so jump to the statement line corresponding to default (that is, the instruction with an offset of 75).

Calculation of the hash value of lunar flying fish: ("lunar flying fish"). HashCode ()

From lines 36 to 75, jump to the instruction to determine whether the hash value is equal or not.

Then call java.lang.String#equals to determine whether the string of switch is equal to the string of the corresponding case.

If equal, the index of the condition is obtained according to which condition, and then each index corresponds to the next specified number of lines of code.

Continue to look down from the offset line 75:

76: tableswitch {/ / 0 to 2 0: 104 1: 115 2: 126 default: 137}

The default statement corresponds to 137 lines, prints the "default" string, and then executes the 145line return command to return.

Determine which line of print statement to execute through tableswitch.

The summary is that the whole process is to first calculate the hash value of the string parameter, determine the range of the hash value, and then determine whether the object is equal or not, and then execute the corresponding code block.

This practice of first judging whether the hash value is equal (it may be the same object / two objects may be equal), and then comparing the equality of objects through equals, is also very common in many JDK source code of Java and other frameworks.

Analyze the problem of null pointer

Disassemble the code in the preface:

Public class Test {public static void main (String [] args) {String param = null; switch (param) {case "null": System.out.println ("match null string"); break; default: System.out.println ("enter default") } public class com.zhou.Test {public com.zhou.Test (); Code: 0: aload_0 1: invokespecial # 1 / / Method java/lang/Object. "": () V 4: return public static void main (java.lang.String []) Code: 0: aconst_null 1: astore_1 2: aload_1 3: astore_2 4: iconst_m1 5: istore_3 6: aload_2 7: invokevirtual # 2 / / Method java/lang/String.hashCode: () I 10: lookupswitch {/ / 1 3392903: 28 Default: 39} 28: aload_2 29: ldc # 3 / / String null 31: invokevirtual # 4 / / Method java/lang/String.equals: (Ljava/lang/Object ) Z 34: ifeq 39 37: iconst_0 38: istore_3 39: iload_3 40: lookupswitch {/ / 10: 60 default: 71} 60: getstatic # 5 / / Field java/lang/System.out:Ljava/io/PrintStream 63: ldc # 6 / / String matches the null string 65: invokevirtual # 7 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V 68: goto 79 71: getstatic # 5 / / Field java/lang/System.out:Ljava/io/PrintStream 74: ldc # 8 / / String enter default 76: invokevirtual # 7 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V 79: return}

You can guess that 3392903 should be the hash of the "null" string.

10: lookupswitch {/ / 1 3392903: 28 default: 39}

We can print its hash value to verify: System.out.println (("null"). HashCode ())

Summarize the overall process:

String param = null; int hashCode = param.hashCode (); if (hashCode = = ("null"). HashCode () & & param.equals ("null")) {System.out.println ("null");} else {System.out.println ("default");}

So the reason for the null pointer is clear at a glance: the instance method of the null object is called.

On how to solve the Switch null pointer exception to share here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report