当泛型方法返回'Nothing'时返回什么,但不能返回null?

问题描述:

假设我有这样的(非常略)库方法:当泛型方法返回'Nothing'时返回什么,但不能返回null?

public static <V> Optional<V> doSomethingWith(Callable<V> callable) { 
    try { 
     return Optional.of(callable.call()); 
    } catch (Exception ex) { 
     // Do something with ex 
     return Optional.empty(); 
    } 
} 

而且我要的东西,没有返回值,如:

Library.</*What1*/>doSomethingWith(() -> { 
     foo(); 
     return /*what2*/; 
    }); 

我的第一本能通用不返回值的方法是制作Void类型并返回null,但是因为结果被封装在Optional中,这会引发异常。

什么是合理的占位符/*What1*//*what2*/看起来不像Integer0完全随机?

我试图避免Optional.ofNullable,因为此处用空表示callable.call()未正常完成。

+3

你不能改变库方法来使用'Optional.ofNullable'吗?如果它始终存在,那么返回可选项有什么意义? –

+0

库方法非常简短。当条件发生时,它实际上可以返回'Optional.empty()'。 –

+0

您可以添加一个合理命名的本地类并返回该类的一个实例 – glee8e

我通常使用Boolean.TRUE来标记成功,但您也可以返回Void.class。两者都很便宜,因为并不是每一个回报都会产生一个新的物品被丢弃。尽管Class<Void>不仅仅是Void它也可以用于标记void之类的内容。

如前所述,您也可以创建自己的Result-class/-enum。您也可以返回Optional.<Void>nothing()。这会导致一些Optional<Optional<Void>>,但也有窍门。

如果您认为上述所有内容都很难看,我担心API可能无法很好地满足您的需求。提出问题/拉请求或寻找其他东西。

+0

我最喜欢枚举选项。特别是因为昨天我只是想知道为什么没有内置(非原始)类型有两种可能性。比较:'Void'有一个可能性:'null','Boolean'有三个:'null','FALSE','TRUE'。 (“对象”当然有无限的可能性。) –

如果您需要一个永远不会使用的泛型参数的类型提示,您可以使用Void,但在某些情况下,JDK也会这样做。转换成RunnableCompletableFuture<T>它使用作废的T.

如果使用Optional.ofNullable那么你可以返回null为what2,这是Void唯一有效的值。

我试图避免Optional.ofNullable,因为此处使用empty来指示callable.call()没有正常完成。

然后,您使用的工具是错误的工具。 CompletionStageCompletableFuture具有正确的语义。

使用Void作为返回类型,这是“无”的合理选择,但实际返回Void的实例。

虽然javadoc for Void说这是:

...一个不可占位符类...

您仍然可以对其进行实例化:

try { 
    Constructor<Void> c = Void.class.getDeclaredConstructor(); 
    c.setAccessible(true); 
    return c.newInstance(); 
} catch (Exception perfunctory) { 
    return null; // won't happen 
} 
+6

不好的建议。当你破解一个'Void'的实例时,你会破坏几个合约,更不用说在将来/备用JDK中导致'不会发生'的可能实现变化发生。 –

+0

@标记哪个合约**,特别是**,被打破?请提供链接等。我坚持认为没有这样的合同,如果将来的版本更改构造函数以使此代码不起作用(非常不可能),那么请担心。 – Bohemian

您还可以创建你的自己类型与Void

public class Result { 
    public static final Result OK = new Result(); 

    private Result(){} 
} 

然后返回Result.OK

如果需要,还可以增强此类型以表示错误。

但也许使用java Void是最好的,如果你不需要任何特殊的。

+0

我会为此使用枚举。 – TheConstructor

+0

这取决于你必须做什么,单身人士你不能管理错误,因为有了它,你将需要一个不同的实例,每次有不同的消息。 – rascio

+0

枚举继承了一些更多的方法(比如'toString'),为什么我通常更喜欢它们用于像所提出的'Result.OK'这样的信号实例。如果在API中使用某个'ResultOrError'类而不是'Optional',那么OP的问题就不存在了。 – TheConstructor