3

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
Shashika
  • 1,606
  • 6
  • 28
  • 47
  • 3
    What exactly is `returnList`? (I can not reproduce this in Java 1.8) – Andreas Fester Jul 08 '16 at 09:33
  • 4
    Also note that there are specific rules for the return type of the `?:` operator, depending on the operand types: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25. Based on that, boxing and unboxing happens in the background. And, BTW, I can reproduce it when I use `Long` as the variable's type to which the result is assigned, but `long` does work. So, please provide an [mcve] so that we have the same code which shows the issue. – Andreas Fester Jul 08 '16 at 09:37
  • 5
    Possible duplicate of [Java 8 - converting an Integer to a long compilation issue](http://stackoverflow.com/questions/27105299/java-8-converting-an-integer-to-a-long-compilation-issue) – jan.supol Jul 08 '16 at 09:38
  • 1
    Please reply to Andreas Fester's question. – Alexey Jul 08 '16 at 09:52
  • 1
    It would probably be worth mentioning your compiler and version. – Didier L Jul 08 '16 at 10:08
  • @AndreasFester returnList is List – Shashika Jul 08 '16 at 10:34
  • @DidierL I'm using the latest JDK avalaible currently jdk1.8.0_91 – Shashika Jul 08 '16 at 10:36
  • 3
    Aren't you using Eclipse? Also, your answer to Andreas does not make it an [mcve]. Please edit the question for that. – Didier L Jul 08 '16 at 10:40
  • 1
    If you method returns `long` (a primitive), why the compiler says: "cannot be converted to `Long`" (a wrapper)? Please provide a more complete code fragment as Didier suggested. – Alexey Jul 08 '16 at 11:08
  • @Alexey Added the complete method. – Shashika Jul 08 '16 at 11:16
  • 1
    So, it's a `Long` ) – Alexey Jul 08 '16 at 11:19
  • @Alexey Why does it work in Java 1.7 – Shashika Jul 08 '16 at 11:32
  • Which Java7 version are you using exactly? It works with OpenJDK 1.7.0_25, but http://ideone.com/IZ4CxN shows the same error when choosing Java7 (I assume they use the latest update) – Andreas Fester Jul 08 '16 at 13:00
  • 1
    @Andreas Fester: that’s a disguise. I tested it by inserting a lambda expression and ideone compiled it, despite Java 7 being selected. So it’s not a Java 7 compiler… – Holger Jul 08 '16 at 14:20
  • @Holger Damn - thanks, I should have checked that. Wonder what thats useful for, then ... – Andreas Fester Jul 11 '16 at 08:28

2 Answers2

4

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
1

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;
Jérèm Le Blond
  • 645
  • 5
  • 23
  • 3
    Yeah, It works that way but why the previous expression don't work as in java 1.7? – Shashika Jul 08 '16 at 09:32
  • Maybe to be more accurate while coding? :) – Jérèm Le Blond Jul 08 '16 at 09:34
  • 2
    @JérèmLeBlond the question is: what rules of the Java language changed so that this doesn't compile anymore in Java 8? Oracle is always extremely careful with backward compatibility so they will not have changed the rules without a very good reason. – Jesper Jul 08 '16 at 09:37
  • I was looking for change log between java 7 & 8 and I didn't see anything about this... – Jérèm Le Blond Jul 08 '16 at 10:57