Tùy chọn.orElse không biên dịch với các loại ẩn danh


8

Tôi đã gặp một vấn đề kỳ lạ khi sử dụng Optionalcác lớp s và ẩn danh:

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() {
        });
    }
}

Hai phương thức đầu tiên không biên dịch với lỗi

java: incompatible types: <anonymous test.Foo.Bar> cannot be converted to <anonymous test.Foo.Bar>

Tôi mong đợi rằng, vì cả hai đều thực hiện giao diện, Barcả ba cách tiếp cận đều hoạt động. Tôi cũng không thể tìm ra lý do tại sao tùy chọn thứ ba khắc phục vấn đề. Bất cứ ai có thể giải thích điều này xin vui lòng?


2
Cái thứ ba sửa lỗi, bởi vì có loại Optional.ofđược sửa Optional<Bar>. Trong tất cả các trường hợp khác, nó là Optional<SubAnonymousSubclassOfBar>. BarMặc dù vậy, tôi cũng mong hai người kia sẽ suy ra giới hạn chung thích hợp là tốt. Nhưng rõ ràng Optional<SomeSubclassOfBar>(bar).orElse(someOtherSubclassOfBar)cần một số cầm tay.
Thilo

Câu trả lời:


7

Bạn có thể bổ sung loại trên hai loại đầu tiên bằng cách sử dụng một nhân chứng loại:

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

Điều này cho phép trình biên dịch thấy rằng bạn đang mong đợi sự trở lại Optional<Bar>, mà #orElse sau đó có thể suy ra để chấp nhận bất kỳBar


5

Bạn cần nói với Tùy chọn rằng bạn muốn có một Thanh cho giao diện đó.

Bar bar = new Bar();
Optional<Bar> o = Optional.of(new Bar() {}).orElse(bar);

1
Tôi biết những gì generic là cho. Tôi chỉ nghĩ javac sẽ suy ra các loại như @Thilo nói.
Mirco

3
Vâng, đến từ Scala, phải đánh vần điều này là một sự khập khiễng. Mặt khác, javacbiên dịch nhanh hơn rất nhiều, vì vậy ...
Thilo

@Mirco nó xâm nhập 'loại anon mở rộng Bar'. Nếu đó không phải là điều bạn muốn, bạn phải nói rõ ý định của mình.
Nicktar

5

Vỏ compiles1

Của bạn Optionalcó loại chung Bar, bởi vì biến barcó loại Bar.

Lớp ẩn danh của loại Foo$1bạn tạo có Bardạng siêu, do đó phương thức biên dịch.

Vỏ doesNotCompile

Ở đây, Optionalcó loại generic Foo$1và bạn đang cố gắng để vượt qua một đối tượng kiểu Foo$2vào orElsemà không có Foo$1như là một loại siêu. Do đó lỗi biên dịch.

Vỏ doesNotCompile2

Tương tự như doesNotCompile, Optionalcó loại generic Foo$1và bạn đang cố gắng để vượt qua bar, một biến kiểu Barthành orElsemà lại không có Foo$1như là một loại siêu.


Tránh những lỗi này

Thêm một nhân chứng cho cuộc gọi của bạn Optional::of. Điều này cung cấp cho Optionalloại chung của bạn 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() {
        });
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.