Java Void类型 - 可能/允许的值?

时间:2016-01-14 13:44:30

标签: java void

1)在Java中,我可以这样做:

Void z = null;

除了null我可以分配给z吗?

之外是否还有其他值?

2)考虑以下代码剪切:

Callable<Void> v = () -> {
    System.out.println("zzz"); 
    Thread.sleep(1000);
    return null;
}; 

这编译好了,但是如果我删除最后一个语句return null;则没有。为什么?毕竟,Void应该意味着没有返回值。

5 个答案:

答案 0 :(得分:8)

来自docs

  

Void类是一个不可实例化的占位符类,用于保存对表示Java关键字void的Class对象的引用。

所以,没有

Void由必须返回一个对象的方法使用,但实际上什么也没有返回。

在Android中使用AsyncTask时可以观察到一个不错的示例,如果您在任务完成后不需要返回任何对象。

然后,您会延长AsyncTask<[your params type], [your progress type], Void>,并在null覆盖中返回onPostExecute

在大多数情况下你不需要它(例如,Runnable通常比Callable<Void>更合适。)

更具体地回答您的问题:

  

但是,如果我删除返回null它不编译?!为什么?

...因为Void仍然是一个对象。但是,它只能具有值null

如果您的方法声明它返回Void,则需要(明确地)返回null

答案 1 :(得分:3)

如果您查看来源:

package java.lang;

public final class Void {
    public static final Class<Void> TYPE = Class.getPrimitiveClass("void");

    private Void() {
    }
}

Void 是:

  • 最后一堂课;
  • 有私有构造函数。

如果不使用 Reflection ,则无法将 null 分配给 Void类型的引用。

答案 2 :(得分:2)

  

在Java中,我可以这样做Void z = null;是否有任何其他值(但为空)我可以分配给z?

如果您创建自己的Void实例,则可以。您可以使用反射或不安全来创建这些,而不是它是一个好主意。

  

但是,如果我删除返回null它不编译?!为什么?毕竟,Void应该只是意味着 - 没有返回类型。

Java区分大小写,这意味着Booleanboolean不是同一类型,也不是VoidvoidVoidvoid的概念包装,但除此之外只是一个你不应该创建任何实例的类。

答案 3 :(得分:1)

也许您要求的是RunnableConsumer - 某些界面没有返回值。 Void仅用于表明除了null之外你不能指望任何其他东西。它仍然只是一个类,而不是关键字或任何特殊的东西。一个无法实例化的类,因此您必须返回null。

答案 4 :(得分:1)

花费很多精力设计lambda表达式来区别对待int/Integer等,以便int->LongInteger->long等兼容。

以类似的方式处理void/Void是可能的(也是可取的),请参阅GoetzForax的评论。 但是,他们没有时间实现java8的想法:(

您可以引入同时为()->void()->Void的适配器类型;它可以稍微简化您的使用案例,请参阅http://bayou.io/release/0.9/javadoc/bayou/util/function/Callable_Void.html

如果你有一个接受()->Void的方法,它就不能与()->void lambdas一起使用。一种解决方法是重载方法以接受()->void。例如,ExecutorService

    submit(Callable<T> task)
    submit(Runnable task)

    ...
        submit( System::gc );   // ()->void

然而,使用函数参数类型进行重载很棘手......上面的示例之所以有效,是因为它们都接受零参数函数。如果函数具有非零args

    foo( Function<String,Void> f )   //  String->Void
    foo( Consumer<String>      f )   //  String->void

它让编译器(和程序员)感到困惑

    foo( str->System.out.println(str) );  // which foo?
    foo( System.out::println );           // which foo?

给定隐式lambda str->expr,编译器需要一个目标类型来理解它。此处的目标类型由方法参数类型给出。如果方法被重载,我们首先需要解决方法重载...这通常取决于参数的类型(lambda)...所以你可以看到它为什么复杂。

(零参数lambda永远不会隐含。所有参数类型都是已知的,因为没有参数。)

lambda规范确实有解决以下情况的条款

    foo( str->{ System.out.println(str); } );
    foo( str->{ System.out.println(str); return null; } );

您可能会争辩说,在上一个例子中,

    foo( str->System.out.println(str) );

由于println(str)返回voidVoid版本显然不合适,因此编译器应该能够解析它。但是,请记住,要了解println(str)的含义,首先必须解析str的类型,即必须首先解决foo的方法重载...

虽然在这种情况下,str明确无误String。不幸的是,lambda设计师决定不能解决这个问题,认为它太复杂了。这是一个严重的缺陷,这就是为什么我们不能重载像Comparator

这样的方法
    comparing( T->U )

  //comparing( T->int )       // overloading won't work well

    comparingInt ( T->int )   // use a diff method name instead