返回一个Void对象

145

如果不是基本类型,那么返回 Void 类型的正确方式是什么?例如,我目前使用 null 作为返回值。

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}

1
我正在使用解释器模式为文件格式编写解释器,但某些表达式没有返回值。 - Robert
3
无法实例化 Void 类型,因此如果你确实需要返回该类型的值,则 null 是唯一的选择。但是,你可能不需要返回任何值,所以 null 应该是可以接受的。 - Jorn
是的,那也是我的逻辑 - 只是想知道是否有更语义化的方法。 - Robert
1
我会像你的示例一样编写代码。这是一个很好的方法。 - David Roussel
7个回答

166
Void类是一个不可实例化的占位符类,它持有代表Java关键字void的Class对象的引用。
因此,下列任何一种方法都可以:
  • 使用Object作为参数类型并返回new Object()或null
  • 使用Void作为参数类型并返回null
  • 使用您自己的NullObject作为参数类型
您不能将此方法设为void,其他任何返回值都会返回“某些东西”。由于忽略了该返回值,因此您可以返回任何内容。

2
那么,通用正确的方法是什么,以实现返回类型为void? - Robert
3
如果您想将null作为void返回,有些情况下需要进行强制转换:(Void) null。 - Patrick
1
return (Void)null; - Alex R
可以从任何方式区分 (Void)null 和 null 吗? - lue

16

Java 8引入了一个新类Optional<T>,可以在这种情况下使用。要使用它,您需要稍微修改代码如下:

interface B<E>{ Optional<E> method(); }

class A implements B<Void>{

    public Optional<Void> method(){
        // do something
        return Optional.empty();
    }
}

这使您能够确保从您的方法中始终获得非空返回值,即使没有任何内容需要返回。当与检测null是否可以或不能返回的工具结合使用时,特别强大,例如 Eclipse @NonNull@Nullable 注释。


12
我认为这个方向是错误的。更好的方法是返回一个更紧密的类型,能够更清晰地传达含义。返回Optional<Void>是无必要的,因为你总是得到一个空的Optional<Void>,所以其他所有方法都是没有意义的。这与使用可选值的原因相反。你使用它是因为可能有值,也可能没有值。此外,编译器不能强制实现method()的正确性。在运行时会出错:return Optional.of(null) - steinybot

3
如果你不需要任何返回值,可以使用void关键词。这适用于编写函数或者执行某些操作。例如:
interface Action<T> {
    public T execute();
}

abstract class VoidAction implements Action<Void> {
    public Void execute() {
        executeInternal();
        return null;
    }

    abstract void executeInternal();
}

或者您可以省略抽象类,在不需要返回值的每个操作中自己执行 return null。

然后,您可以像这样使用这些操作:

假设有一个方法

private static <T> T executeAction(Action<T> action) {
    return action.execute();
}

你可以这样调用

String result = executeAction(new Action<String>() {
    @Override
    public String execute() {
        //code here
        return "Return me!";
    }
});

或者,对于空操作(请注意,您没有将结果分配给任何内容)
executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});

2
这与我已经拥有的有什么不同?它仍然只返回 null,就像我建议的那样。 - Robert
为什么你需要返回其他任何东西呢?我想要表达的是,你不需要返回值,所以你返回什么并不重要。我在编辑中试图澄清这一点。 - Jorn

2

当然,为了演示,可以使用反射创建Void实例:

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something

        try {
            Constructor<Void> voidConstructor = Void.class.getDeclaredConstructor();
            voidConstructor.setAccessible(true);
            return voidConstructor.newInstance();
        } catch (Exception ex) {
            // Rethrow, or return null, or whatever.
        }
    }
}

你在生产环境中可能不会这样做。


1

如果更改安全管理器,就可以创建 Void 的实例,像这样:

static Void getVoid() throws SecurityException, InstantiationException,
        IllegalAccessException, InvocationTargetException {
    class BadSecurityManager extends SecurityManager {
    
        @Override
        public void checkPermission(Permission perm) { }
    
        @Override
        public void checkPackageAccess(String pkg) { }

    }
    System.setSecurityManager(badManager = new BadSecurityManager());
    Constructor<?> constructor = Void.class.getDeclaredConstructors()[0];
    if(!constructor.isAccessible()) {
        constructor.setAccessible(true);
    }
    return (Void) constructor.newInstance();
}

显然这并不是很实用或安全的,但是如果您能够更改安全管理器,则会返回一个 Void 的实例。

0

我发现了获取Void类实例的新方法。这是一个本地代码,其中env分配了一个Void对象。然后将该对象返回给Java代码。对象存在于Java代码中,并可用作实际实例。

JNIEXPORT jobject JNICALL Java_main_Main_getVoid(JNIEnv *env, jobject obj){
    jclass voidclass=env->FindClass("java/lang/Void");
    return env->AllocObject(voidclass);
}

2
你的回答并没有在问题的背景下提供帮助。这个问题是关于在Java中正确使用Void类,而不是如何创建Void类型对象的问题。 - Ralf Wagner

0

没有通用类型可以告诉编译器一个方法不返回任何内容。

我相信惯例是在继承时使用 Object 作为类型参数

或者

将类型参数向上传递,然后让您的类的用户使用 Object 实例化,并将对象分配给使用类型通配符 ? 类型的变量:

interface B<E>{ E method(); }

class A<T> implements B<T>{

    public T method(){
        // do something
        return null;
    }
}

A<?> a = new A<Object>();

1
这是使用泛型设置返回类型为void的惯例吗?对我来说看起来并不是很void。 - Robert
我相信这是正确的方法。任何使用A<?>类的用户都无法利用method()返回的值。 - Christopher Oezbek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接