Do you really know the three-mesh operator in Java?Original
2018-04-27
the inquisitiveHollisHollis
Hollis
number Hollischuang
Function Introduction a person who has a unique quest for coding.
The trinocular operator is something we often use in code, a= (b==null?0:1), so that a line of code can be used in place of a if-else to make the code crisp and readable.
However, the trinocular operator also has a certain language specification. When used improperly, it can lead to unexpected problems. This article introduces a pit I've stepped on myself.
One or three mesh operator
for conditional Expressions b?x:y
, the condition B is evaluated first and then judged. If the value of B is true, the value of x is computed, the result of the operation is the value of x, otherwise, the value of Y is evaluated and the result of the operation is Y. A conditional expression never evaluates both X and Y. The conditional operator is right-associative, that is, a right-to-left grouping is calculated. For example, A?b:c?d:e will be executed by a?b: (c?d:e).
Second, automatic packing and automatic unpacking
basic data type Auto-boxing ( autoboxing
), unpacking ( unboxing
) is a feature that has been available since J2SE 5.0.
In general, when we are creating an object instance of a class, we do this: Class A = new Class (parameters); When we create an integer object, we can do this: integer i = +; ( note: and int i = 100; there is a difference )
In fact, when executing the code above, the system executes for us: Integer i = integer.valueof (+); This is not a discussion of how this principle is implemented (when unpacking, when to box), and also the difference between ordinary data types and object types.
We can understand that when we write our own code in accordance with the Assembly (Disassembly) box specification, the compiler will automatically help us to dismantle (install) the box. So, what is the problem with this automatic unpacking box that is not controlled by the programmer?
Iii. Review of issues
First, take a look at the following code through your experience. If the results you get are consistent with the results of the post analysis (and you know the principle), then ignore this article. If it's not the same, please explore with me.
Public Static voidMainString[] args) {
map<String,Boolean> map =NewHashmap<> ();
Booleanb = map! =NULL? Map.get ("Test") :false;
System.out.println (b);
}
The above code is a class of code that we may often write without notice (we all love using the three-mesh operator in many cases).
In general, we assume that the resulting value of the above code, Boolean B, should be null. Because the value of Map.get ("test") is null, and B is an object, the resulting result is null.
However, the above code throws the NPE:
exception in thread " main " java.lang.NullPointerException
The first thing to be clear is that since the null pointer has been reported, there must be some way to invoke a null object in some places. In this short two lines of code, there seems to be only one method call map.get("test")
, but we all know that the map has been initialized beforehand, not NULL, so where is the null pointer?
We next Anti-compilation the code for a moment. Let's see what the code we wrote became after the compiler processed it. the post-compilation code is as follows:
Public Static voidMainStringArgs[]) {
Map map =NewHashMap ();
Booleanb =Boolean. valueOf (Map = =NULL?false: ((Boolean) Map.get ("Test"). Booleanvalue ());
System.out.println (b);
}
After reading this post-compilation code, we will probably know where the problem is. ((Boolean) hashmap.get ("Test")). Booleanvalue () the execution process and results are as follows:
Hashmap.get ("Test")->null;
(Boolean) null->null;
Null.booleanvalue () Error
OK, the problem is finally fixed. Obviously, the Map.get ("test") in the source code above is compiled into a
(Boolean) map.get ("test"). Booleanvalue (), which is an automatic unpacking operation.
So, why is there an automatic unpacking happening here? How can this problem be solved?
Four, the principle analysis
By looking at the post-compilation code, we pinpoint the problem, and we can conclude that the reason for the NPE is that the three-mesh operator and the automatic unboxing cause null pointer exceptions.
So, why does this code automatically unboxing? This is actually the syntax specification for the trinocular operator. See jls-15.25, summarized below:
If the second and third operands have the same same type (which may being the null type), then this is the type of the conditional Expression.
If one of the second and third operands is of the primitive type T, and the type of the the the the the 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 that the other is a reference type, then the type O f The conditional expression is this reference type.
In a nutshell: When the second, third-digit operand is the base type and the object, the object is disassembled as the base type.
So, the result is this: because the three-mesh operator is used, and the second, third-digit operands are basic types and objects, respectively. Therefore, the object is unboxing, because the object is null, so when the unboxing process called Null.booleanvalue (), the time of the report to the NPE.
V. Problem solving
If the code says so, there is no error:
Map<String,Boolean> map =Newhashmap<String,Boolean> ();
Booleanb = (map!=NULL? Map.get ("Test") :Boolean. FALSE);
It's guaranteed. The second third-digit operand of the three-mesh operator is the object type. This will not result in an automatic unboxing operation, and the results of B obtained by the above code are null.
PS: The example in this article is just to make it easier for readers to understand that the three-mesh operator causes automatic unboxing, and may not be used directly in the code. However, my own code does happen to have similar problems. Here to simplify, in order to clarify the principle.
Possible problems with the three-mesh operator in Java