【问题标题】:Cannot cast int to long in Java 8在 Java 8 中无法将 int 转换为 long
【发布时间】:2016-07-08 09:28:55
【问题描述】:

我正在将我的项目升级到 Java 1.7 到 1.8。当我编译我的代码时,它会给出一个compile error,因为 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;

    }

我很困惑为什么 0 不能在 java 1.8 中转换为 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

【问题讨论】:

标签: java casting java-8


【解决方案1】:

数值条件表达式受制于“Binary Numeric Promotion”,这就是下面代码可以编译的原因:

Long long1   = null;
Integer int1 = null;
Long long2 = true? long1: int1;

由于两个备选方案都具有数字类型,因此应用了数字提升,它首先将值拆箱,然后将扩大转换应用到 int 操作数,因此条件表达式的结果类型为 long。只有在此之后,才会对Long 进行拳击。

因此,由于拆箱和装箱步骤,上面的代码具有抛出NullPointerException 而不是直接将在long1 中找到的对象分配给long2 的不直观行为。


这同样适用于Long 和int 的组合,当一个操作数的结果是方法调用时,例如

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;
}

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

The specification 说:

…

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

    • 独立形式的表达式(第 15.2 节),其类型可转换为数字类型(第 4.2 节,第 5.1.8 节)。

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

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

    • 一个方法调用表达式(第 15.12 节),为其选择的最具体的方法(第 15.12.2.5 节)具有可转换为数字类型的返回类型。

    • 数值条件表达式

请注意,与 Java 7 相比,由于引入了“独立形式”表达式,这与受目标类型影响的“多边形表达式”相反。

要检查方法调用是独立表达式还是多边形表达式,我们必须参考JLS §15.12:

如果满足以下所有条件,则方法调用表达式是一个多边形表达式:

  • 调用出现在赋值上下文或调用上下文中(第 5.2 节、第 5.3 节)。

  • 如果调用是合格的(即除第一个之外的任何形式的 MethodInvocation),则调用会省略标识符左侧的 TypeArguments。

  • 由以下小节确定的要调用的方法是泛型的(第 8.4.4 节),并且具有提及至少一个方法类型参数的返回类型。

否则,方法调用表达式是一个独立的表达式。

在我们的例子中,最后一个项目符号不适用。该方法是泛型类的成员,但它本身是非泛型的,因为它没有声明类型参数,所以它的返回类型不引用方法的类型参数,因为没有.

也就是说,这个方法调用是一个独立的表达式,有一个数值返回类型,所以条件表达式是一个数值条件表达式,应该像其他例子一样进行二进制数值提升。


请注意,所有最近的 Java 9 实现都会编译此代码,就像 Java 6 和 Java 7 实现一样。

【讨论】:

    【解决方案2】:

    尝试在末尾添加“L”:

    returnList != null && returnList.size()>0 ? returnList.get(0) : 0L;
    

    或者如果'returnList.get(0)'返回一个int,试试:

    returnList != null && returnList.size()>0 ? (long)returnList.get(0) : 0L;
    

    【讨论】:

    • 是的,它是这样工作的,但为什么前面的表达式不像在 java 1.7 中那样工作?
    • 可能在编码时更准确? :)
    • @JérèmLeBlond 问题是:Java 语言的哪些规则发生了变化,以至于在 Java 8 中不再编译? Oracle 在向后兼容性方面总是非常小心,因此他们不会在没有充分理由的情况下更改规则。
    • 我正在寻找 java 7 和 8 之间的更改日志,但我没有看到任何关于此的...
    猜你喜欢
    • 2015-04-27
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-19
    • 1970-01-01
    相关资源
    最近更新 更多