1)在Java中,我可以这样做:
Void z = null;
除了null
我可以分配给z
吗?
2)考虑以下代码剪切:
Callable<Void> v = () -> {
System.out.println("zzz");
Thread.sleep(1000);
return null;
};
这编译好了,但是如果我删除最后一个语句return null;
则没有。为什么?毕竟,Void
应该意味着没有返回值。
答案 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区分大小写,这意味着Boolean
和boolean
不是同一类型,也不是Void
和void
。 Void
是void
的概念包装,但除此之外只是一个你不应该创建任何实例的类。
答案 3 :(得分:1)
也许您要求的是Runnable
或Consumer
- 某些界面没有返回值。 Void
仅用于表明除了null之外你不能指望任何其他东西。它仍然只是一个类,而不是关键字或任何特殊的东西。一个无法实例化的类,因此您必须返回null。
答案 4 :(得分:1)
花费很多精力设计lambda表达式来区别对待int/Integer
等,以便int->Long
与Integer->long
等兼容。
以类似的方式处理void/Void
是可能的(也是可取的),请参阅Goetz和Forax的评论。
但是,他们没有时间实现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)
返回void
,Void
版本显然不合适,因此编译器应该能够解析它。但是,请记住,要了解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