Possible problems with ternary operator in Java

Do you really understand the ternary operator in Java?

2018-04-27 Hollis Hollis _

The ternary operator is often used in our code, a= (b==null?0:1); Such a line of code can replace an if-else, which can make the code clean and readable.

 

However, ternary operators also have certain language specifications. It can lead to unexpected problems when used inappropriately. This article introduces a pit that I have stepped on myself.

 

One, the ternary operator

For conditional expressions b?x:y, the condition b is calculated first, and then the judgment is made. If the value of b is true, the value of x is calculated, and the result of the operation is the value of x; otherwise, the value of y is calculated, and the result of the operation is the value of y. A conditional expression never evaluates both x and y. Conditional operators are right-associative, that is, they are evaluated in groups from right to left. For example, a?b:c?d:e will be executed as a?b:(c?d:e).

 

2. Automatic packing and automatic unpacking

Autoboxing ( autoboxing) and unboxing ( ) of primitive data types are unboxingfunctions provided since J2SE 5.0.

 Generally, when we want to create an object instance of a class, we will do this: Class a = new Class(parameters); When we create an Integer object, we can do this: Integer i = 100; ( Note: and int i = 100 ; there is a difference  ) 

 

In fact, when the above code is executed, the system executes it for us:  Integer i = Integer.valueOf(100) ; I will not discuss how this principle is implemented here (when to unbox, when to pack), The difference between ordinary data types and object types.

We can understand that when the code we write ourselves conforms to the packing (unpacking) specification, the compiler will automatically unpack (pack) us. So, will there be any problems with this automatic unpacking (packing) that is not controlled by the programmer?

 

3. Problem Review

First, take a look at the following code from your existing experience. If the results you get are consistent with the results of the analysis below (and you know how), then please ignore this article. If not, please explore with me.

public static void main(String[] args) {
    Map<String, Boolean> map = new HashMap<>();
    Boolean b = map != null ? map.get("test") : false;
    System.out.println(b);
}

The above code is a type of code that we may often write without paying attention (we love to use the ternary operator in many cases).

Under normal circumstances, we will think that the final value of Boolean b in the above code should be null. Because the value of map.get("test") is null, and b is an object, the result will be null.

However, the above code throws NPE:

Exception in thread "main" java.lang.NullPointerException

First of all, it is clear that since a null pointer is reported, some methods of a null object must be called somewhere. In these short two lines of code, it seems that there is only one method call map.get("test"), but we all know that the map has been initialized in advance and will not be Null, so where is the null pointer?

Let's decompile the code next. See what the code we wrote looks like after being processed by the compiler. The decompiled code is as follows:

public static void main(String args[]){
   Map map = new HashMap();
   Boolean b = Boolean.valueOf(map == null ? false : ((Boolean)map.get("test")).booleanValue());
   System.out.println(b);
}

 

After reading this decompiled code, we can probably know where the problem is after analysis. The execution process and results of ((Boolean)hashmap.get("test")).booleanValue()  are as follows:

hashmap.get("test")->null;

(Boolean)null->null;

null.booleanValue()->Error

Well, the problem is finally located. Obviously, map.get("test") in the above source code is compiled into

(Boolean)map.get("test").booleanValue(), which is an automatic unboxing operation.

 

So, why is auto-unboxing happening here? How to solve this problem?

 

Four, principle analysis

By looking at the decompiled code, we can accurately locate the problem. After analysis, we can draw the conclusion that the cause of NPE should be the null pointer exception caused by the ternary operator and automatic unboxing.

So why is this code automatically unboxed? This is actually the syntax specification for the ternary operator. See jls-15.25 , summarised below:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.


If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

Simply put: when the second and third operands are the basic type and the object, respectively, the object will be unboxed for the basic type to operate.

So, the result is: due to the use of the ternary operator, and the second and third operands are primitive types and objects, respectively. Therefore, when the object is unboxed, since the object is null, NPE is reported when null.booleanValue() is called during the unboxing process.

 

Five, problem solving

If the code is written like this, no error will be reported:

Map<String,Boolean> map =  new HashMap<String, Boolean>();
Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);

It is to ensure that the second and third operands of the ternary operator are all object types. This way no automatic unboxing occurs, and the result of b obtained by the above code is null.

PS: The examples in this article are just to make it easier for readers to understand that the ternary operator will cause automatic unboxing, which may not be used directly in the code. However, a similar problem did occur with my own code. It is simplified here for clarity.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325043942&siteId=291194637