【问题标题】:returning a Void object返回一个 Void 对象
【发布时间】:2011-01-25 09:40:00
【问题描述】:

返回Void 类型的正确方法是什么,当它不是原始类型时?例如。我目前使用 null 如下。

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

class A implements B<Void>{

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

【问题讨论】:

  • 我正在使用解释器模式为文件格式编写解释器,但有些表达式没有返回值
  • 没有办法实例化 Void 类型,所以如果你真的必须返回那种类型的东西,null 是你唯一的选择。但是,您可能不需要任何返回值,所以 null 应该没问题。
  • 是的,这也是我的逻辑——只是想知道是否有更语义化的方式
  • 我会像您的示例一样对其进行编码。这是一个很好的方法。

标签: java generics return-value


【解决方案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 的实例。

【讨论】:

    【解决方案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.
            }
        }
    }
    

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

    【讨论】:

      【解决方案3】:

      Java 8 引入了一个新类Optional&lt;T&gt;,可以在这种情况下使用。要使用它,您需要稍微修改您的代码,如下所示:

      interface B<E>{ Optional<E> method(); }
      
      class A implements B<Void>{
      
          public Optional<Void> method(){
              // do something
              return Optional.empty();
          }
      }
      

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

      【讨论】:

      • 我认为这是错误的方向。最好返回一个更受约束的类型,以更清晰地传达含义。由于与您给出的相同原因,不需要返回Optional&lt;Void&gt; 的东西,您总是得到一个空的Optional&lt;Void&gt;,因此所有其他方法都毫无意义。这与为什么应该使用可选值相反。您使用它是因为它可能有价值,也可能没有价值。此外,编译器无法强制 method() 正确实现它。这将在运行时失败:return Optional.of(null).
      【解决方案4】:

      没有泛型类型会告诉编译器方法不返回任何内容。

      我相信约定是在继承时使用 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>();
      

      【讨论】:

      • 这是使用泛型将返回类型设置为 void 的约定吗?对我来说它看起来不是很 void?
      • 我相信这是要走的路。 A&lt;?&gt; 类的任何用户都无法使用 method() 的返回值。
      【解决方案5】:

      如果你只是不需要任何东西作为你的类型,你可以使用 void。这可用于实现功能或操作。然后你可以这样做:

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

      或者您可以省略抽象类,并在每个不需要自己返回值的操作中返回 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!";
          }
      });
      

      或者,对于 void 操作(请注意,您没有将结果分配给任何东西)

      executeAction(new VoidAction() {
          @Override
          public void executeInternal() {
              //code here
          }
      });
      

      【讨论】:

      • 这与我已有的有什么不同?它仍然只是返回 null,就像我建议的那样
      • 为什么还要退货?我要说明的是你不需要返回值,所以你返回什么并不重要。我试图通过我的编辑来澄清这一点。
      【解决方案6】:

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

      所以以下任何一个都足够了:

      • 使用Object 参数化并返回new Object()null
      • 使用Void 参数化并返回null
      • 使用您的 NullObject 进行参数化

      你不能使这个方法void,其他任何东西都会返回一些东西。由于忽略了某些内容,因此您可以返回任何内容。

      【讨论】:

      • 那么实现 void 返回类型的一般正确方法是什么?
      • 如果你想将 null 作为 void 返回,你需要在某些情况下强制转换:(Void) null
      • return (Void)null;
      • 能否以任何方式将 (Void)null 与 null 区分开来?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      • 2015-06-03
      • 2014-05-27
      • 2014-05-22
      • 2017-03-06
      • 1970-01-01
      相关资源
      最近更新 更多