I'm upgrading my project to Java 1.7 to 1.8. When I compile my code, it gives a compile error as int cannot cast to long.
Here is the expression which returns a primitive long.
public Long getOrganizationIdByUser(String userId){
Query query = getSession().getNamedQuery("getOrganizationIdByUser");
query.setString("id", userId!=null?_userId.toLowerCase():null);
List<Long> returnList = query.list();
return returnList!=null&&returnList.size()>0?returnList.get(0):0;
}
I've confused why 0 cannot cast to long in java 1.8 since this is a basic concept in java and also it works fine in java 1.7.
Error
error: incompatible types: bad type in conditional expression
[javac] return returnList!=null&&returnList.size()>0?returnList.get(0):0;
[javac]
[javac] int cannot be converted to Long
Numeric conditional expressions are subject to “Binary Numeric Promotion”, which is the reason why the following code can be compiled:
Long long1 = null;
Integer int1 = null;
Long long2 = true? long1: int1;
Since both alternatives have a numeric type, the numeric promotion applies, which will first unbox the values, then apply the widening conversion to the int operand, so the conditional expression has a result type of long. Only after, the boxing to Long happens.
So the code above has the unintuitive behavior of throwing a NullPointerException instead of directly assigning the object found in long1 to long2, due to the unboxing and boxing steps.
The same applies to the combination of Long and int, also when the result of the one operand is a method invocation, e.g.
static Long test() {
return Math.random()<0.5? test(): 0;
}
can be compiled without problems. So what’s the difference? In the example
public Long test() {
List<Long> returnList = new ArrayList<Long>();
return returnList!=null&&!returnList.isEmpty()? returnList.get(0): 0;
}
the method invocation is made on an instance of a generic class.
The specification says:
…
If both the second and the third operand expressions are numeric expressions, the conditional expression is a numeric conditional expression.
For the purpose of classifying a conditional, the following expressions are numeric expressions:
An expression of a standalone form (§15.2) with a type that is convertible to a numeric type (§4.2, §5.1.8).
A parenthesized numeric expression (§15.8.5).
A class instance creation expression (§15.9) for a class that is convertible to a numeric type.
A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has a return type that is convertible to a numeric type.
A numeric conditional expression
Note that this has been changed compared to Java 7, due to the introduction of the “standalone form” expression, which is the opposite of the “poly expression” which is subject to target typing.
To check whether the method invocation is a stand-alone expression or a poly expression, we have to refer to JLS §15.12:
A method invocation expression is a poly expression if all of the following are true:
The invocation appears in an assignment context or an invocation context (§5.2, §5.3).
If the invocation is qualified (that is, any form of MethodInvocation except for the first), then the invocation elides TypeArguments to the left of the Identifier.
The method to be invoked, as determined by the following subsections, is generic (§8.4.4) and has a return type that mentions at least one of the method's type parameters.
Otherwise, the method invocation expression is a standalone expression.
In our case, the last bullet does not apply. This method is a member of a generic class, but it is itself not generic as it doesn’t declare type parameters, so it’s return type doesn’t refer to a method’s type parameter, as there is none.
In other words, this method invocation is a stand-alone expression, having a numeric return type, so the conditional expression is a numeric conditional expression, and should be subject to Binary Numeric Promotion, just like the other examples.
Note that all recent Java 9 implementation do compile this code, just like the Java 6 and Java 7 implementations do.
Try adding 'L' at the end :
returnList != null && returnList.size()>0 ? returnList.get(0) : 0L;
Or if 'returnList.get(0)' return an int, try:
returnList != null && returnList.size()>0 ? (long)returnList.get(0) : 0L;
Related
I'm reading a chapter on lambdas in Herbert Schildt's "Java: The Complete Reference" and there are quite a few references to "lambda target type" and "target type context":
A functional interface defines the target type of a
lambda expression. Here is a key point: a lambda expression can be used only
in a context in which its target type is specified.
Or:
As mentioned earlier, a lambda expression is not executed on its own.
Rather, it forms the implementation of the abstract method defined by the
functional interface that specifies its target type. As a result, a lambda
expression can be specified only in a context in which a target type is
defined. One of these contexts is created when a lambda expression is
assigned to a functional interface reference. Other target type contexts
include variable initialization, return statements, and method arguments, to
name a few.
Yet another:
The functional interface associated with a lambda expression can be generic. In
this case, the target type of the lambda expression is determined, in part, by the type argument or arguments specified when a functional interface
reference is declared.
Can someone please help me understand what's meant by lambda target type?
For instance, in (int n) -> n % 2 == 0 is int the lambda's target type?
Or in:
interface MyInterface<T> {
T func();
}
MyInterface<String> myInt = () -> { return "123"; }
What is the lambda's target type? Is it String or MyInterface<String>? And what is the lambda's context here?
I read several posts on SO on the topic but still cannot fully understand the notions.
Thanks.
One of the definitions of "target" (taken from here) is:
a result or situation that you intend to achieve.
You can say the result a lambda expression intends to achieve is to implement some functional interface. Hence that functional interface can be seen as the target of that lambda expression, and the type of the functional interface is the target type.
Hence the target type is the type of the functional interface implemented by the lambda expression.
The target type can be inferred based on the context in which the lambda expression is used:
If the lambda expression is assigned to a functional interface reference variable, the type of that variable is the target type.
If the lambda expression is returned by some method, the return type of the method is the target type.
If the lambda expression is passed as an argument to a method, the type of the corresponding argument expected by the method is the target type.
In
(int n) -> n % 2 == 0
the target type is unknown. If you assign this expression to some functional interface reference, that would be the target type.
In
MyInterface<String> myInt = () -> { return "123"; }
the target type is MyInterface<String>.
I decided to read a bit more about lamdas and found an excellent book "Beginning Java 8 Language Features: Lambda Expressions, Inner Classes, Threads, I/O, Collections and Streams" by Kishori Shiran.
I will just cite a few paragraphs:
Every expression in Java has a type; so does a lambda expression. The type of a lambda expression is a functional interface type. When the abstract method of the functional interface is called, the body of the lambda expression is executed.
Consider the lambda expression that takes a String parameter and returns its length:
(String str) -> str.length()
What is the type of this lambda expression? The answer is that we do not know. By looking at the lambda expression, all you can say is that it takes a String parameter and returns an int, which is the length of the String. Its type can be any functional interface type with an abstract method that takes a String as a parameter and returns an int. The following is an example of such a functional interface:
#FunctionalInterface
interface StringToIntMapper {
int map(String str);
}
The lambda expression represents an instance of the StringToIntMapper functional interface when it appears in the assignment statement, like so:
StringToIntMapper mapper = (String str) -> str.length();
In this statement, the compiler finds that the right-hand side of the assignment operator is a lambda expression. To infer its type, it looks at the left-hand side of the assignment operator that expects an instance of the StringToIntMapper interface; it verifies that the lambda expression conforms to the declaration of the map() method in the StringToIntMapper interface; finally, it infers that the type of the lambda expression is the StringToIntMapper interface type.
This lambda expression may be of different functional interface types depending on the context in which it is used. There are two types of expressions in Java - standalone expressions and poly expressions
A standalone expression is an expression whose type can be determined by the expression without knowing the context of its use. A poly expression is an expression that has different types in different contexts. The compiler determines the type of the expression. The contexts that allow the use of poly expressions are known as poly contexts. All lambda expressions in Java are poly expressions. You must use it in a context to know its type. Poly expressions existed in Java prior to Java 8 and lambda expressions. For example, the expression new ArrayList<>() is a poly expression. You
cannot tell its type unless you provide the context of its use.
The compiler infers the type of a lambda expression. The context in which a lambda expression is used expects a type, which is called the target type. The process of inferring the type of a lambda expression from the context is known as target typing. Consider the following pseudo code for an assignment statement where a variable of type T is assigned a lambda expression:
T t = <LambdaExpression>;
The target type of the lambda expression in this context is T. The compiler uses the following rules to determine whether the <LambdaExpression> is assignment compatible with its target type T:
T must be a functional interface type.
The lambda expression has the same number and type of parameters as the abstract method of T. For an implicit lambda expression, the compiler will infer the types of parameters from the abstract method of T.
The type of the returned value from the body of the lambda expression is assignment compatible to the return type of the abstract method of T.
If the body of the lambda expression throws any checked exceptions, those exceptions must be compatible with the declared throws clause of the abstract method of T. It is a compile-time error to throw checked exceptions from the body of a lambda expression, if its target type's method does not contain a throws clause.
You should understand "target type" as the functional interface as which the function is (intended to be) used.
Think about this: what is this lambda expression expected to be and how can it be used?
() -> "123";
As the book notes it, this expression can't be used on its own. It needs to be associated with a functional interface.
Now, what functional interface can be the type of a lambda expression is picked up from the context. This is where the "target type" of the lambda expression means something.
Consider these examples:
Example 1:
void printString(Supplier<String> supplier) {
System.out.println(supplier.get());
}
You can call that with
printString(() -> "123");
In this case, you mean the type of () -> "123" to be Supplier<String>. That's the target type of () -> "123" in this context.
Example 2:
MyInterface<String> myInt = () -> "123";
As you can see, an identical lambda expression was used, but its target type is now MyInterface<String>.
Likewise, you can declare another functional interface that has the same signature as MyInterface.func() and assign the very same lambda expression to it. The target type changes in these varied contexts.
Let's look at the simple Java code in the following snippet:
public class Main {
private int temp() {
return true ? null : 0;
// No compiler error - the compiler allows a return value of null
// in a method signature that returns an int.
}
private int same() {
if (true) {
return null;
// The same is not possible with if,
// and causes a compile-time error - incompatible types.
} else {
return 0;
}
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.temp());
System.out.println(m.same());
}
}
In this simplest of Java code, the temp() method issues no compiler error even though the return type of the function is int, and we are trying to return the value null (through the statement return true ? null : 0;). When compiled, this obviously causes the run time exception NullPointerException.
However, it appears that the same thing is wrong if we represent the ternary operator with an if statement (as in the same() method), which does issue a compile-time error! Why?
The compiler interprets null as a null reference to an Integer, applies the autoboxing/unboxing rules for the conditional operator (as described in the Java Language Specification, 15.25), and moves happily on. This will generate a NullPointerException at run time, which you can confirm by trying it.
I think, the Java compiler interprets true ? null : 0 as an Integer expression, which can be implicitly converted to int, possibly giving NullPointerException.
For the second case, the expression null is of the special null type see, so the code return null makes type mismatch.
Actually, its all explained in the Java Language Specification.
The type of a conditional expression is determined as follows:
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.
Therefore the "null" in your (true ? null : 0) gets an int type and then is autoboxed to Integer.
Try something like this to verify this (true ? null : null) and you will get the compiler error.
In the case of the if statement, the null reference is not treated as an Integer reference because it is not participating in an expression that forces it to be interpreted as such. Therefore the error can be readily caught at compile-time because it is more clearly a type error.
As for the conditional operator, the Java Language Specification §15.25 “Conditional Operator ? :” answers this nicely in the rules for how type conversion is applied:
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.
Does not apply because null is not int.
If one of the second and third operands is of type boolean and the type of the
other is of type Boolean, then the type of the conditional expression is boolean.
Does not apply because neither null nor int is boolean or Boolean.
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.
Does not apply because null is of the null type, but int is not a reference type.
Otherwise, if the second and third operands have types that are convertible
(§5.1.8) to numeric types, then there are several cases: […]
Applies: null is treated as convertible to a numeric type, and is defined in §5.1.8 “Unboxing Conversion” to throw a NullPointerException.
The first thing to keep in mind is that Java ternary operators have a "type", and that this is what the compiler will determine and consider no matter what the actual/real types of the second or third parameter are. Depending on several factors the ternary operator type is determined in different ways as illustrated in the Java Language Specification 15.26
In the question above we should consider the last case:
Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).
This is by far the most complex case once you take a look at applying capture conversion (§5.1.10) and most of all at lub(T1, T2).
In plain English and after an extreme simplification we can describe the process as calculating the "Least Common Superclass" (yes, think of the LCM) of the second and third parameters. This will give us the ternary operator "type". Again, what I just said is an extreme simplification (consider classes that implement multiple common interfaces).
For example, if you try the following:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
You'll notice that resulting type of the conditional expression is java.util.Date since it's the "Least Common Superclass" for the Timestamp/Time pair.
Since null can be autoboxed to anything, the "Least Common Superclass" is the Integer class and this will be the return type of the conditional expression (ternary operator) above. The return value will then be a null pointer of type Integer and that is what will be returned by the ternary operator.
At runtime, when the Java Virtual Machine unboxes the Integer a NullPointerException is thrown. This happens because the JVM attempts to invoke the function null.intValue(), where null is the result of autoboxing.
In my opinion (and since my opinion is not in the Java Language Specification many people will find it wrong anyway) the compiler does a poor job in evaluating the expression in your question. Given that you wrote true ? param1 : param2 the compiler should determine right away that the first parameter -null- will be returned and it should generate a compiler error. This is somewhat similar to when you write while(true){} etc... and the compiler complains about the code underneath the loop and flags it with Unreachable Statements.
Your second case is pretty straightforward and this answer is already too long... ;)
CORRECTION:
After another analysis I believe that I was wrong to say that a null value can be boxed/autoboxed to anything. Talking about the class Integer, explicit boxing consists in invoking the new Integer(...) constructor or maybe the Integer.valueOf(int i); (I found this version somewhere). The former would throw a NumberFormatException (and this does not happen) while the second would just not make sense since an int cannot be null...
Actually, in the first case the expression can be evaluated, since the compiler knows, that it must be evaluated as an Integer, however in the second case the type of the return value (null) can not be determined, so it can not be compiled. If you cast it to Integer, the code will compile.
private int temp() {
if (true) {
Integer x = null;
return x;// since that is fine because of unboxing then the returned value could be null
//in other words I can say x could be null or new Integer(intValue) or a intValue
}
return (true ? null : 0); //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
//value can be Integer
// then null is accepted to be a variable (-refrence variable-) of Integer
}
How about this:
public class ConditionalExpressionType {
public static void main(String[] args) {
String s = "";
s += (true ? 1 : "") instanceof Integer;
System.out.println(s);
String t = "";
t += (!true ? 1 : "") instanceof String;
System.out.println(t);
}
}
The output is true, true.
Eclipse color codes the 1 in the conditional expression as autoboxed.
My guess is the compiler is seeing the return type of the expression as Object.
I am trying to create a generic method that adds any list of numeric types in java. I would like to be able to use this method to add Integers, Doubles, Longs etc..
The below does not seem to work. I get compilation exceptions in eclipse saying:
The operator + is undefined for the argument type(s) Number, T
What could be the problemo? Thank you in advance.
public static <T extends Number> T sum(ArrayList<T> nums){
Number retVal = 0.0;
for (T val : nums){
retVal = retVal+ val;
}
return (T) retVal;
}
Consider what the Java Language Specification says about the additive + operator
If the type of either operand of a + operator is String, then the
operation is string concatenation.
Otherwise, the type of each of the operands of the + operator must be
a type that is convertible (§5.1.8) to a primitive numeric type, or a
compile-time error occurs.
Number is not a type that is convertible to a primitive. You therefore cannot use the + operator with variables of that type.
Consider using a different type or overloading your methods for each numeric type.
instead of retVal = retVal+ val;
Use like below.
retVal = retVal.doubleValue()+ val.doubleValue();
Consider what you are asking for. You want a collection into which you can place numbers of arbitrary types, and perform operations like sum(). There are eight distinct number subtypes (BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short, not counting the atomic versions).
You will have noticed that java.lang.Number has no arithmetic methods, like add() or multiply(). You can't just go adding up instances of Number subclasses willy-nilly; you must consider each possible pairing, decide the rules for converting one or both to a common type for which addition is defined, and then decide what the result type is.
Then this has to be applied for each number you add to the running total. This is a non-trivial design task.
Luckily you can piggy-back off the design decisions already present for primitive types in the JLS, but it's still going to be a lot of work.
Why is the compiler able to determine the generic type parameter for an
assignment, but not for the ternary operator (?)?
I have a question regarding the compiler being able to deduce the generic type
parameter in case of a "direct" assignment but failing in case of the ternary
operator (?). My examples uses Guava's Optional class, to make my point, but
I think the underlying issue is generic and not restricted to Optional.
Optional has a generic function absent():
public static <T> Optional<T> absent();
and I can assign an Optional<T> to an Optional<Double>:
// no compiler error
final Optional<Double> o1 = Optional.absent();
How does the compiler realize, that T should be Double in this case. Because
when using the ternary operator (?), I need to tell the compiler specifically
to us Integer as the generic parameter
// Type mismatch: cannot convert from Optional<capture#1-of ? extends Object> to Optional<Integer>
final Optional<Integer> o2 = true
? Optional.of(42)
: Optional.<Integer>absent();
otherwise I get the following error
Type mismatch: cannot convert from Optional<capture#1-of ? extends Object> to Optional<Integer>
Why is there a difference between a "direct" assignement and using the ternary
operator? Or is there something else I am missing?
Because of type inference rules, it appears the ternary expression does not infer the type parameter from the return type. The type of the ternary expression depends on the types of its operands. But one of the operands has undetermined type parameter (Optional.absent()). At that point the ternary expression still does not have a type, so it cannot influence the type parameter.
You can also look into this bug report for more information. You can look into the JLS .
The type of the conditional expression is the result of applying capture conversion (??5.1.10) to lub(T1, T2)
Here what the JLS says :
If the method result occurs in a context where it will be subject to assignment conversion to a type S, then let R be the declared result type of the method, and let R' = R[T1 = B(T1) ... Tn = B(Tn)] where B(Ti) is the type inferred for Ti in the previous section, or Ti if no type was inferred.
The Problem is that the result of the ternery Operator is assigned to o2.
The compiler can't deduce the type across multiple operations.
Basically I think you write the short form of:
Optional<?> tmp = true ? Optional.of(42): Optional.absent();
final Optional<Integer> o2 = tmp;
The conversion of the second line is the problem.
Given the generic method:
<T> List<T> getGenericList(int i) {...}
the following code compiles without any warning:
public List<String> getStringList(boolean b){
if(b)
return getGenericList(0);
else
return getGenericList(1);
}
but this one generates 'Type mismatch' compilation error:
public List<String> getStringList(boolean b) {
return (b) ? getGenericList(0) : getGenericList(1);
}
Why?
This is NOT a generics problem, but a consequence of the way the compiler has to infer the type of the ternary expression.
It happens the same with this equivalent code. This code works:
public byte function(boolean b){
if(b)
return 1;
else
return 2;
}
While this doesn't:
public byte function(boolean b) {
return (b) ? 1 : 2;
}
The reason is that when the compiler tries infer the type of this expression
return (b) ? 1 : 2;
It first has to obtain the type of each one of the operands, and check if they are compatible (reference) to evaluate wether the ternary expression is valid or not. If the type of the "return" were propagated to automatically cast or promote each one of the operands, it could lead to resolve the type of a ternary expression differently depending on the context of this expression.
Given that the type of the "return" cannot be propagated to the operands, then in the menctioned case:
return (b) ? getGenericList(0) : getGenericList(1);
the binding of the generic type cannot be done, so the type of each one of the operands is resolved to List<Object>. Then the compiler concludes that the type of the whole expression is List<Object>, which cannot be automatically casted to List<Integer> (because they are not compatible types).
Whereas this other one
return getGenericList(0);
It applyes the type of the "return" to bind the generic type T, so the compiler concludes that the expression has a List<String> type, that can be returned safely.
this is because of an edge case in generic type deduction
in the explicit returns the return type of each getGenericList can be trivially set to List (outward info propagates inwards)
but in the conditional it goes the other way the type of it is the more general of the two possibilities (inward info propagates outwards)
the compiler could deduct the info implicitly here but it's not buildin yet file a bug report if you really need it
When the trinary operator is evaluated, it's result is not bound to any type. It's as if you just call:
getGenericList(0);
Try compiling the above, the compilation will fail.
In return statement, the result is bound to your function's return type and is evaluated.
Edit:
I've mistaken. The above statement compiles, but the result type is evaluated as (List < Object > ). Try compiling:
List<String> l = (List<String>)getGenericList(0);
This one will fail.
This is because javac needs to infer T, but T does not appear in argument types.
static<T> T foo(){ .. }
foo(); // T=?
Only in 2 cases, javac can infer T from the context
String s = foo(); // #1: assignment
String bar(){
return foo(); // #2: return
In other cases, javac won't, and T is simply inferred as Object
But this type of methods are dangerous anyway. How could your method know it's time to return List<String>, not a list of something else? There's no info about T available to you.
It looks likes its just inefficient compilation.
As Maurice said, generally, the compiler determines the type of T by function arguments. In this case there aren't any.
However, because getStringList() returns List<String> and it calls return getGenericList(), the compiler is smart enough to forward the return type of getStringList to getGenericList and determine the type in that manner.
My guess is that in the ternary operator, it's doesn't bind in reverse, but rather finds the common denominator in each substatement and assigns that as the output of the ternary statement, and the compiler isn't smart enough to pass the expected output of the ternary statement into its substatements.
Note, you can directly pass the type parameter into the function call, and it works fine, ie:
return b ? this.<String> getGenericList(0) : this.<String> getGenericList(1);
compiles properly.