在Java 8中无法将int转换为long

3

我正在将我的项目从Java 1.7升级到1.8。当我编译我的代码时,它会给出一个“编译错误”,提示“int无法转换为long”。

这里是返回原始类型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;

    }

我很困惑为什么在Java 1.8中0不能转换为long,因为这是Java中的基本概念,并且在Java 1.7中也可以正常工作。
错误
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

3
returnList 究竟是什么?(我无法在 Java 1.8 中复现这个问题) - Andreas Fester
4
请注意,?:运算符的返回类型有特定规则,取决于操作数类型:http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25。基于此,装箱和拆箱发生在后台。另外,当我使用`Long`作为变量类型并将结果赋值给它时,我也能重现这个问题,但使用`long`则没有问题。因此,请提供一个 [mcve],以便我们能够看到相同的代码并观察问题。 - Andreas Fester
5
可能是Java 8 - converting an Integer to a long compilation issue的重复问题。 - jan.supol
1
可能值得一提的是您所使用的编译器及其版本。 - Didier L
3
你没有使用Eclipse吗?另外,你对Andreas的回答并没有把问题变成一个最小化可复现的示例。请编辑问题。 - Didier L
显示剩余10条评论
2个回答

4
数字条件表达式受到“二进制数值提升”的影响,这就是以下代码能够被编译的原因。
Long long1   = null;
Integer int1 = null;
Long long2 = true? long1: int1;

由于两个备选项都具有数字类型,因此应用数字提升,该过程将首先取消装箱值,然后将宽化转换应用于int操作数,因此条件表达式的结果类型为long。之后才进行Long的装箱。
因此,上述代码具有令人费解的行为,会抛出NullPointerException而不是直接将在long1中找到的对象分配给long2,这是由于取消装箱和装箱步骤导致的。
同样适用于Longint的组合,即使一个操作数的结果是方法调用,例如。
static Long test() {
    return Math.random()<0.5? test(): 0;
}

可以编译而无问题。那么有什么区别呢?在这个例子中。
public Long test() {
    List<Long> returnList = new ArrayList<Long>();
    return returnList!=null&&!returnList.isEmpty()? returnList.get(0): 0;
}

该方法调用是在泛型类的实例上进行的。

规范说:

...

  • 如果第二个和第三个操作数表达式都是数字表达式,则条件表达式是一个数字条件表达式。
    为了分类条件,以下表达式是数字表达式:

    • 具有可转换为数字类型(§4.2、§5.1.8)的类型的独立形式(§15.2)的表达式。

    • 括号内的数字表达式(§15.8.5)。

    • 可转换为数字类型的类的类实例创建表达式(§15.9)。

    • 选定最具体方法(§15.12.2.5)的返回类型可转换为数字类型的方法调用表达式(§15.12)。

    • 数字条件表达式

请注意,与Java 7相比,由于引入了“独立形式”表达式,因此已经发生了更改,这与受目标类型控制的“多态表达式”相反。
要检查方法调用是独立表达式还是多态表达式,我们必须参考JLS §15.12:
如果满足以下所有条件,则方法调用表达式是多态表达式:
- 调用出现在赋值上下文或调用上下文中(§5.2、§5.3)。 - 如果调用有资格(即除第一个之外的任何形式的MethodInvocation),则省略Identifier左侧的TypeArguments。 - 将要调用的方法(由以下子节确定)是通用的(§8.4.4),并且具有提到方法的至少一个类型参数的返回类型。
否则,方法调用表达式是独立表达式。
在我们的情况下,最后一条不适用。该方法是通用类的成员,但它本身不是通用的,因为它没有声明类型参数,所以它的返回类型不引用方法的类型参数,因为没有类型参数。
换句话说,该方法调用是一个独立的表达式,具有数字返回类型,因此条件表达式是数字条件表达式,并且应该像其他示例一样接受二进制数字提升。
请注意,所有最近的Java 9实现都可以编译此代码,就像Java 6和Java 7实现一样。

1
尝试在末尾添加'L':
returnList != null && returnList.size()>0 ? returnList.get(0) : 0L;

如果'returnList.get(0)'返回一个整数,尝试:
returnList != null && returnList.size()>0 ? (long)returnList.get(0) : 0L;

3
可以这样工作,但为什么以前的表达式在Java 1.7中不起作用呢? - Shashika
也许在编写代码时更准确? :) - Jérèm Le Blond
2
@JérèmLeBlond 这个问题是:Java语言的哪些规则发生了变化,以至于在Java 8中无法编译?Oracle一直非常注重向后兼容性,因此他们不会没有非常充分的理由就改变规则。 - Jesper
我正在寻找Java 7和8之间的更改日志,但我没有看到任何相关内容... - Jérèm Le Blond

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接