Java:如何使用Optional.empty()编译?

Java:如何使用Optional.empty()编译?,java,java-8,Java,Java 8,这似乎是一个非常愚蠢的问题,但我不明白为什么使用Optional编译: import java.util.Optional; public class Driver { static void foo(Optional<String> x) { } public static void main() { foo(Optional.empty()); } } 但是,代码编译得非常好。显然,我在这里的思维过程是不正确的……但在哪里呢 让我澄

这似乎是一个非常愚蠢的问题,但我不明白为什么使用
Optional
编译:

import java.util.Optional;

public class Driver {
    static void foo(Optional<String> x) { }

    public static void main() {
        foo(Optional.empty());
    }
}
但是,代码编译得非常好。显然,我在这里的思维过程是不正确的……但在哪里呢


让我澄清一下我在这里寻找的答案…我知道什么是类型推断。我不明白的是,它是如何在这里发生的,以及语言从Java7到Java8发生了什么变化。例如,这段代码在Java 8中编译得非常好,但在Java 7中编译失败:

final class Opt<T> {
    private final T value;

    Opt(T x) {
        value = x;
    }

    public static <T> Opt<T> empty() {
        return new Opt<T>(null);
    }
}

public class Driver {
    static void bar(Opt<String> x) { }

    public static void main() {
        bar(Opt.empty());
    }
}
final class Opt{
私人最终T值;
Opt(tx){
值=x;
}
公共静态Opt empty(){
返回新选项(空);
}
}
公务舱司机{
静态空心条(Opt x){}
公共静态void main(){
条(Opt.empty());
}
}

当您必须处理重载之类的事情时,在Java8中这是如何工作的?Java语言规范中是否有一个特定的章节讨论这类事情?

Java 8添加了类型接口,这意味着它将根据表达式的使用方式计算出表达式的类型

一个明显的例子是

Object o = () -> System.out.println("Hello World"); 
不编译,因为它不知道表达式的类型

Runnable r = () -> System.out.println("Hello World"); 

Object o = (Runnable) () -> System.out.println("Hello World"); 

很好。ie表达式的类型会因其使用方式而改变。

这是因为在Optional中定义empty()方法的方式:

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
公共静态可选空(){
@抑制警告(“未选中”)
可选t=(可选)空;
返回t;
}
注意上面的方法类型参数:

public static<T> Optional<T> empty() {
             ^^^ method type parameter
公共静态可选空(){
^^^方法类型参数
这意味着当调用empty()时,它将把T绑定到它的调用者的上下文(在您的大小写字符串中)。有关更多信息,请参阅Java教程中本页中有关目标类型的部分:


这是因为编译器进行类型推断

当编译器读取时:

static void foo(Optional<String> x) { }

public static void main() {
    foo(Optional.empty());
}
staticvoidfoo(可选x){
公共静态void main(){
foo(可选的.empty());
}
  • 它知道
    Optional.empty()
    T
    作为参数
  • 它知道
    foo
    需要一个
    可选的
  • 它推断
    T
    String
它是在泛型引入时引入的,也许它的机制是通过Java8的
javac
改进的


请注意,这取决于编译器:ECJ(EclipseJDT编译器)不理解Javac所理解的相同java源代码(但是,它们确实编译“相同”的字节码)。

由于您的问题的这一部分没有得到解决,我将尝试总结一下Java7和Java8之间的变化

Java7已经有了类型推断,例如,您可以编写

List<String> list=Collections.emptyList();
List List=Collections.emptyList();

List getList(){
返回集合。emptyList();
}
但这种类型的推断相当有限,例如,不起作用的(除其他外)是:

List List=Collections.unmodifiableList(Collections.emptyList());

List getList(){
返回条件?新建ArrayList():Collections.emptyList();
}
这两个示例现在在Java 8下工作。此新功能称为目标类型推断,因为它现在使用目标的类型来查找适当的类型参数。除了使嵌套方法调用和条件有效外,如上面的示例中所示,它还修复了以下示例:

List<Number> numbers=Arrays.asList(1, 2, 3, 4);
List number=Arrays.asList(1,2,3,4);
如上所述,Java7也有类型推断,但在本例中,它将根据传递给
asList
的参数推断
List
作为表达式的结果类型,并因此生成错误

相反,Java 8具有目标类型推断,并将使用赋值的目标类型推断
列表
作为表达式的类型,并发现整个语句是有效的,因为您可以使用
整数
对象,其中
数字
是预期的


请注意,
Optional.empty()
Collections.emptyList()
使用相同类型的泛型构造。我在示例中使用了后者,因为它已经存在于Java 7中。

类型推断是一件很酷的事情,它没有有效地回答这个问题。+1关于类型参数。但对推断部分不太确定。我的意思是,类型参数声明非常明确。
List<String> getList() {
    return Collections.emptyList();
}
List<String> list=Collections.unmodifiableList(Collections.emptyList());
List<String> getList() {
    return condition? new ArrayList<>(): Collections.emptyList();
}
List<Number> numbers=Arrays.asList(1, 2, 3, 4);