Optional.orElse 不使用匿名类型编译

Mir*_*rco 8 java anonymous-class optional

我在使用Optionals 和匿名类时遇到了一个奇怪的问题:

public class Foo {
    interface Bar {
    }

    void doesNotCompile() {
        Optional.of(new Bar() {
        }).orElse(new Bar() {
        });
    }

    void doesNotCompile2() {
        final Bar bar = new Bar() {
        };
        Optional.of(new Bar() {
        }).orElse(bar);
    }

    void compiles1() {
        final Bar bar = new Bar() {
        };
        Optional.of(bar).orElse(new Bar() {
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

前两种方法不编译会报错

java: incompatible types: <anonymous test.Foo.Bar> cannot be converted to <anonymous test.Foo.Bar>
Run Code Online (Sandbox Code Playgroud)

我预料到了,因为这两种Bar方法都实现了接口,所以这三种方法都可以工作。我也无法弄清楚为什么第三个选项解决了这个问题。任何人都可以解释一下吗?

Rog*_*gue 8

您可以使用类型见证补充前两个的类型:

Optional.<Bar>of(new Bar(){}).orElse(new Bar(){});
Run Code Online (Sandbox Code Playgroud)

这允许编译器看到您期望返回Optional<Bar>,然后 #orElse 可以推断接受任何Bar


Nic*_*tar 5

您需要告诉 Optional 您想要该接口的 Bar。

Bar bar = new Bar();
Optional<Bar> o = Optional.of(new Bar() {}).orElse(bar);
Run Code Online (Sandbox Code Playgroud)

  • 是的,来自 Scala,必须将其拼写出来有点蹩脚。另一方面,“javac”编译速度要快得多,所以...... (3认同)

Mar*_*arv 5

案件 compiles1

Optional有泛型类型Bar,因为变量bar有类型Bar

Foo$1您创建的匿名类型类具有Bar超类型,因此该方法可以编译。

案件 doesNotCompile

在这里,Optional具有泛型类型,Foo$1并且您正试图将类型的对象传递Foo$2orElse其中没有Foo$1作为超类型的对象。因此编译错误。

案件 doesNotCompile2

类似doesNotCompileOptional具有泛型类型Foo$1和你试图传递bar,类型的变量BarorElse再次不具有Foo$1的超类型。


避免这些错误

将类型见证添加到您的Optional::of. 这为您提供Optional了通用类型Bar

public class Foo {

    interface Bar {
    }

    void doesNotCompile() {
        Optional.<Bar>of(new Bar() {
        }).orElse(new Bar() {
        });
    }

    void doesNotCompile2() {
        final Bar bar = new Bar() {
        };
        Optional.<Bar>of(new Bar() {
        }).orElse(bar);
    }

    void compiles1() {
        final Bar bar = new Bar() {
        };
        Optional.of(bar).orElse(new Bar() {
        });
    }
}
Run Code Online (Sandbox Code Playgroud)