获取异常 ClassCastException java.lang.Integer 在使用 Optional (Java 8) 时无法转换为 java.lang.Long,否则不会

Getting an exception ClassCastException java.lang.Integer cannot be cast to java.lang.Long while using Optional (Java 8) but not otherwise

我有一个 returns 长的函数。如果我使用 Optional 但不会以其他方式抛出,则会抛出 CastClassException。看下面的代码-

public static Object returnNull() {
    return null;
}

public static long getLong(){
    return (long) Optional.ofNullable(returnNull()).orElse(0);
}

public static void main(String[] args) {
    System.out.println(getLong());
}

如果我运行上面的代码我得到这个错误

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

所以从上面看来,orElse(0) 正在创建一个值为 0 的 Integer 对象,但无法将其大小写为 long(原始),这会引发错误(这是针对 Long 对象的)。

但是,如果我在没有 Optional 的情况下这样做,它不会给出错误。像这样

public static void main(String[] args) {
        Integer i = 0;
        long l = (long) i;
        System.out.println(l);
}

上面没有报错,打印了0。 我知道我可以通过这样做来解决 Optional 的问题 .orElse(0L)

但我不是在寻找消除此错误的解决方案,而是想了解为什么在使用 Optional 时会出现上述错误,而在其他情况下不会出现。

这些是你展示的不同的东西。基本上一个小的重构让事情更容易掌握,我猜:

public static long getLong(){
    Object opt = Optional.ofNullable(returnNull()).orElse(0);
    return (long) opt;
}

因此,您的另一个示例实际上应该写成(并且它会因相同的异常而失败):

    Integer i = 0;
    Object obj = i;
    long l = (long) obj;

实现你想要的:

public static long getLong(){
    return (long) (int)Optional.ofNullable(returnNull()).orElse(0);
}

为什么会出现错误?

您可以将原语 int 隐式转换为原语 long

您不能将 Integer 对象转换为 Long 对象。 Integer 不是 Long 的子类(两者都是 Number 的子类)。你想这样做吗? orElse() 被声明为将泛型类型 T 作为参数,因此是一个对象。因此 Java 将您的 0 自动装箱为 Integer。因为 0 是一个 int。这也解释了为什么 0L 有效:现在 Java 自动装箱到 Long。这是自动装箱会使事情变得不清楚的地方。

我们可以避免 0L 中的 L 吗?

有点啰嗦,但我觉得很干净:

public static long getLong(){
    return Optional.ofNullable(returnNull())
            .stream()
            .map(obj -> (Long) obj)
            .mapToLong(Long::longValue)
            .findAny()
            .orElse(0);
}

坦率地说,我会选择您已经拥有的 0L。我的尝试变得冗长的一个原因是 Optional 没有 mapToLong 方法,所以我将 Optional 转换为流(0 或 1 个元素)并返回到 OptionalLong。它起作用的原因是 OptionalLong.orElse() 以原语 long 作为参数,所以这里 Java 将我的原语 int, 0, 转换为 long.

这是另一个工作变体:

public static long getLong(){
    return ((Number) Optional.ofNullable(returnNull()).orElse(0)).longValue();
}

我正在利用 LongInteger 都是 NUmber 并且 longValue 方法是在 Number 超类中声明的。