Java ternary operator function overloading [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java conditional operator ?: result type
NullPointerException through auto-boxing-behavior of Java ternary operator
Say I have two functions:
f(MyObject o) { ... }
f(int i) { ... }
And I call them like this:
f(someCondition ? 10 : null);
This compiles, but when I run it I get a null pointer exception (sorry I'm not sure on which condition). Some my questions are:
Why does it even compile? What is the type of foo ? 10 : null?
It clearly doesn't call the "correct" functions because that wouldn't cause an NPE. So which function is it calling? Does it do f((MyObject)10); or f((int)null)?

First of all, the problem doesn't have anything to do with the fact that you have overloaded versions of f. If you only have the version of f that takes an int, you get the same problem.
The thing is that both possible results of the ternary expression (before and after the :) must have the same type, because the whole expression condition ? expr1 : expr2 must have a single type. You can't have this expression evaluate to one type of condition is true, and another type if it is false.
So, the Java compiler is going to see if it can convert expr1 and expr2 to a single type. Note that int cannot be null (because it's a primitive type). However, 10 can be converted to Integer via autoboxing, and an Integer can also be null. So the type of the whole ternary expression is determined to be of type Integer. The result is either an Integer that contains the value 10 or an Integer that is null.
Step two is that you pass this Integer to f. Because f takes an int, it is auto-unboxed.
If you auto-unbox an Integer that is null, you get a NullPointerException - that's what happens here.

The type is Integer - an auto boxing is done to the 10.
f(int) is called, because it is the only accepted cast from Integer available (assuming no other overloads)
When you try to cast a null to an int - you get your NPE.
2. f(Object) is called since Integer is an Object. This is called reference type widening
(sorry for the initial mistake, read it as f(Object))

Related

What value does a Method Invocation Expression for a function with void as a return type evaluate to?

The oracle java tutorial states: (emphasis by me)
An expression is a construct made up of variables, operators, and method invocations, which are constructed according to the syntax of the language, that evaluates to a single value.
Given a function
public void doNothing() { }
what values does the Method Invocation Expression doNothing() evaluate to?
I'm wondering this because in my understanding void suggests that this function doesn't return anything.
doNothing() is a method invocation, not an expression. As you quoted, an expression is a construct made up of variables, operators, AND method invocations... that evaluates to a single value. It would be the same as asking if a word, or a phrase is a sentence.
Consider the Map#put(K,V) method. The invocation of this method by itself, even when it returns a value, does not represent an expression in itself.
1 Map<String, Integer> numbers = new HashMap<>();
2 Integer oldVal = numbers.put("one", 1); // not an expression
3 boolean notNull = oldVal != null); // an expression
The main reason why the code on line 2 is not an expression is because no evaluation is being done. Line 2 is a simple method invocation, even though it returns a value. In contrast, line 3 is an expression because an evaluation is being done (the comparison of the notNull variable against null.
1 int value1 = 1 + 2; // an expression
2 int value2 = 5 * 2; // an expression
3 if (value1 == value2) {...} // an expression
In the above snippet, all 3 lines contain an expression. The obvious is line 3 (value1 == value2). The other two are mathematical expressions. Why? Because each one is a construct that has two operands, and an operator.
Going back to the method doNothing(), the invocation of this method cannot be used to construct an expression because it doesn't return a value. Therefore, it cannot be used to build an evaluation.
I hope this helps clarify what an expression is.
The Java Language Specification is the authoratative source, rather than a tutorial.
When an expression in a program is evaluated (executed), the result
denotes one of three things:
A variable (§4.12) (in C, this would be called an lvalue)
A value (§4.2, §4.3)
Nothing (the expression is said to be void)
Thus your doNothing() call is an expression, and your intuition is correct - it returns nothing.
Void expressions are subject to limitations:
An expression denotes nothing if and only if it is a method invocation
(§15.12) that invokes a method that does not return a value, that is,
a method declared void (§8.4). Such an expression can be used only as
an expression statement (§14.8) or as the single expression of a
lambda body (§15.27.2), because every other context in which an
expression can appear requires the expression to denote something.

Why is Java evaluating the wrong side of ternary operation?

I might miss some simple explanation, but the following line throws a NullPointerException:
Long sum = true
?
fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice())
:
(long) fiscalDocument.getReceipt().getAmount();
While
Long sum = true
?
fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice())
:
null
does not. I would also like to mention that
fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice())
does not throw an exception on its own, while
(long) fiscalDocument.getReceipt().getAmount()
does.
Is the second side evaluated? Or am I butchering something?
EDIT
Some additional info, asked in the comments:
fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) returns null.
The return type of fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) is Long.
The return type of fiscalDocument.getReceipt().getAmount() is Integer.
If I emit the explicit (long) conversion, the behavior is the same.
Edit 2
A minimal reproducible example: Long val =true ? (Long) null: Integer.valueOf(1);. This was partially suggested by the answer of MC Emperor and partially suggested by comments. Of course, this example already somewhat answers the question, since the second expression does not need to throw an exception, as it turns out.
If foo has type Long and bar has type long, then true ? foo : bar has type long, and is equivalent to true ? foo.longValue() : bar. As the Java Language Specification puts it:
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.
(In your case, T is long, and "the result of applying boxing conversion (§5.1.7) to T" is Long.)
The fact that you try to put the result in a Long variable doesn't change that fact; it just gives you the equivalent of Long.valueOf(true ? foo.longValue() : bar), with unboxing followed by boxing.
In your case, foo == null, so the unboxing throws a NullPointerException, so the boxing never happens.
Well, Java only evaluates the left expression, as the condition is true.
You said that fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) in itself does not throw an NullPointerException.
The only thing I can think of, is that fiscalDocumentUtil.getFullValue(fiscalDocument.getInvoice()) returns null. Reproducible with:
Long sum = true ? null : (long) 23L;
Because one of the operands is a primitive, the other one is subject to boxing conversion, in this case, unboxed to long.

Why does this chained conditional operator throw NPE?

Boolean isTrue = condition1 ? true : (
id == null ? null : condition2);
When condition1 returns true, the code runs fine(makes sense), but when condition1 is false, the code fails with a null pointer exception.
Try it yourself - https://www.ideone.com/epj9Jd
This is slightly confusing and doesn't make sense. An explanation for this would be appreciated.
Boolean isTrue = condition1 ? true : (
id == null ? null /* <- HERE*/ : condition2);
OK, so this is a bit gnarly. The problem is due to the null value introduced at the point labeled HERE being unboxed.
Why?
Because the type of condition1 ? true : ... is the type of the 2nd operand; i.e. boolean. Therefore the subexpression id == null ? null : condition2 which is Boolean has to be unboxed to a boolean.
But unboxing a null gives you a NPE.
Interesting. I would have expected better type inference here.
Unfortunately, the rules for typing of conditional expressions involving boxed types were solidified in Java 5 when autoboxing / unboxing were added to the language. That was 15 (?) years before Java got significant support for type inferencing.
Once the rules were solidified, they couldn't be changed ... without breaking backwards compatibility.
(But actually this is not a type inference problem. The typing is fine. The real problem here is that there are two possible semantics for this, one that involves unboxing null and the other that doesn't. The JLS rules for typing conditionals mean that the first one is used in this case.)

parameters in this function call are not understood [duplicate]

This question already has answers here:
What is the Java ?: operator called and what does it do?
(17 answers)
Closed 8 years ago.
This function is supposed to take two parameters, however there are characters included that I do not understand what they mean. What is the value of "?". What are the two parameters in this function, I know panel.id is one of them . any link to a library that explain them well ? thank you
setPanelType(panel.id, ((encType) ? PANEL_ST_ENC : PANEL_NORMAL))
The duplicate question posted here might be explaining what the "?" operator is. However I was not sure if it is used differently in a function parameter call. This question is not a duplicate of any.
You've run in to something called the "conditional operator"*. It's basically a short way of writing an if-statement.
For example:
String var;
var = 1 > 0 ? "It's bigger than 0" : "It's 0 or smaller";
Is the same as:
String var;
if(1 > 0){
var = "It's bigger than 0";
}else{
var = "It's 0 or smaller";
}
* It's also sometimes called the "ternary" operator, but that's not quite correct. It's a "ternary operator" (an operator that accepts three operands, just like the multiplication operator * is a binary operator because it accepts two operands), but in theory there could be others. In fact, I think it's the only ternary operator in Java or JavaScript (at least for now).
This syntax is shorthand for a conditional action in Javascript.
(condition) ? (true action) : (false action)
Related: JavaScript ternary operator example with functions
The '?' means Ternary Operator as said above, encType is a boolean variable.
setPanelType(panel.id, ((encType) ? PANEL_ST_ENC : PANEL_NORMAL))
is equals to:
if (encType)
setPanelType(panel.id, PANEL_ST_ENC))
else
setPanelType(panel.id, PANEL_NORMAL))

The expressions which evaluate to a boolean value can not be concatenated with a String in Java. Why? [duplicate]

This question already has answers here:
Getting strange output when printing result of a string comparison
(3 answers)
Closed 2 years ago.
Let's see the following simplest code snippet in Java.
final public class Parsing
{
public static void main(String[] args)
{
int p=10;
int q=10;
System.out.println(p==q);
}
}
The above code in Java is fine and displays true as both p and q of the same type (int) contain the same value (10). Now, I want to concatenate the argument of println() so that it contains a new line escape sequence \n and the result is displayed in a new line as below.
System.out.println("\n"+p==q);
Which is not allowed at all because the expression p==q evaluates a boolean value and a boolean type in Java (not Boolean, a wrapper type) can never be converted to any other types available in Java. Therefore, the above mentioned statement is invalid and it issues a compile-time error. What is the way to get around such situations in Java?
and surprisingly, the following statements are perfectly valid in Java.
System.out.println("\n"+true);
System.out.println("\n"+false);
and displays true and false respectively. How? Why is the same thing in the statement System.out.println("\n"+p==q); not allowed?
You have to add parentheses () around p==q (the way you write it, it will be interpreted as ("\n"+p) == q, and String cannot be compared to a boolean). This operator precedence is desired for expressions like
if(a+b == c+d)
etc. So,
System.out.println("\n"+(p==q));
Should work just fine.
System.out.println("\n"+p==q);
compiler treat it as
System.out.println(("\n"+p)==q);
Use
System.out.println("\n"+(p==q));
Which is not allowed at all because the expression p==q evaluates a boolean value and a boolean type in Java (not Boolean, a wrapper type) can never be converted to any other types available in Java.
This is completely wrong. Concatenating anything to a String is implemented by the compiler via String.valueOf(), which is also overloaded to accept booleans.
The reason for the compiler error is simply that + has a higher operator precedence than ==, so your code is equivalent to
System.out.println(("\n"+p)==q);
and the error occurs because you have a String and an int being compared with ==
On the other hand, this works just as intended:
System.out.println("\n"+(p==q));
The order of precedence of operators means that your expression gets evaluated as
("\n" + p) == q
It is nonsensical to compare a string to an int so compilation fails, try:
"\n" + (p == q)
Ah. The statement is wrong.
System.out.println("\n"+(p==q));
~Dheeraj

Categories