在不存在Optional的情况下,我一直在写特定的例外投掷者。
例如:
Optional<?> optional = ...;
if (!optional.isPresent()) {
throw new MyException();
}
Object result = optional.get();
我发现这段代码不是很流利,尤其是使用bang(!)。我更喜欢写一些类似的东西:
Optional<?> optional = ...;
Object result = optional.orThrow(MyException.class);
我还没有找到番石榴这样的捷径吗?
答案 0 :(得分:21)
作为Guava开发人员,让我尝试在这里解压缩逻辑。直接回答问题的原始问题和评论主题:
绝对是这样,我们试图强迫Guava用户尊重我们良好的编程习惯标准。 (我们的标准强烈受到例如Effective Java的影响。)
那就是说,我同意在这个特定问题中你所指的行为有很好的用例:“如果缺席,就抛出异常。”也许你正在实现一个可以双向访问的类 - 一个带有Optional返回值的方法,一个假定值总是存在的方法,否则抛出异常。例如,Deque接口提供peek,poll和offer的特殊值和异常抛出版本。
所有这一切,据我所知,真正的番石榴方式是......
if (value.isPresent()) {
return value.get();
} else {
throw new MyException();
}
您提出的“orThrow”方法需要反射(!!),不允许您使用有用的消息等自定义异常。“正常方式”是完全可读且更有效的。
有时候Guava没有提供明确的支持,因为对于那些用例,我们认为最好只采用“正常方式”。我想这就是这种情况。
答案 1 :(得分:16)
Java 8的Optional
具有允许所请求行为的orElseThrow(Supplier)
方法,这是值得的。
它的用法如下:
Optional<Object> reference = Optional.empty()
reference.orElseThrow(MyOwnException::new); // Throws a new MyOwnException
此外,还添加了Java 10中的方法orElseThrow()
,如果没有值,则抛出NoSuchElementException
。
Optional<Object> reference = Optional.empty();
reference.orElseThrow(); // Throws a new NoSuchElementException
答案 2 :(得分:13)
这是另一种不添加Guava的方法:
Object result = optional.or(new Supplier() {
public Object get() {
throw new MyException();
}
});
必须取消选中MyException,但这确实允许您将参数传递给其构造函数。当然,如果您正在做很多事情,您可以将供应商存储在某个地方,并在您需要的地方使用它。
Object result = optional.or(SomethingIsMissing.INSTANCE);
答案 3 :(得分:2)
我认为这不属于图书馆。我发现很难找到一个接收异常实例的库,以防万一没有按预期运行,特别是因为在很多情况下异常必须有一条消息指示出了什么问题。
话虽这么说,你可以创建自己的Optional类来满足你的需要。或者,您可以创建自己的OptionalHelper类,其中有一个方法可以执行您想要的操作:
public class OptionalHelper {
public <T> T valueOrThrow(final Optional<T> optional) throws MyException {
if (optional.isPresent()) {
return optional.get();
} else {
throw new MyException();
}
}
}
编辑:
假设您有一个自定义类,它接收您需要检查的参数/字段名称,您可以采用类似于Preconditions的更好方法:
public class OptionalHelper {
public <T> T valueOrFail(final Optional<T> optional, final String fieldName) throws OptionalNotPresentError {
if (optional.isPresent()) {
return optional.get();
} else {
throw new OptionalNotPresentError(fieldName);
}
}
}
答案 4 :(得分:1)
这对我有用(没有反思,只是类型推断):
public class ExceptionSupplier<T, E extends RuntimeException> implements Supplier<T> {
private final E exception;
private ExceptionSupplier(E exception) {
this.exception = exception;
}
public static <T, E extends RuntimeException> ExceptionSupplier<T, E> throwA(E exception) {
return new ExceptionSupplier<T, E>(exception);
}
public static <T, E extends RuntimeException> ExceptionSupplier<T, E> throwA(@SuppressWarnings("UnusedParameters") Class<T> class_, E exception) {
return new ExceptionSupplier<T, E>(exception);
}
@Override
public T get() {
throw exception;
}
}
用法:
Something something = optionalSomething.or(throwA(Something.class, new SomeException()));
这可能会进一步扩展,但对于我的用例,它足够且易于理解。
答案 5 :(得分:0)
决定:不 - 太贵,不是常见的模式,可以使用!isPresent(),throw
由于optional.orThrow(new Exception())
对性能不利,我更喜欢静态导入,这与@timk 's answer类似。
Result result = optional.or(throwException());
等于
Result result = optional.or(SomeSupplier.throwException());
静态方法
public static Supplier<Result> throwException() {
return new Supplier<Result>() {
@Override
public Result get() {
throw new RuntimeException();
}
};
}
===========
堆栈跟踪看起来像
Exception ... RuntimeException
at SomeSupplier$1.get(SomeSupplier.java:line where throw RuntimeException)
at SomeSupplier$1.get(SomeSupplier.java:1)
at com.google.common.base.Absent.or(Absent.java:60)
at line where call optional.or(throwException());
答案 6 :(得分:0)
聚会晚了一点,但这是在番石榴里做这件事的一种优雅方式:
Optional<?> optional = ...;
Object result = optional.or(supplyError(MyException::new));
使用以下辅助方法:
public static Supplier supplyError(Supplier<Error> errorSupplier) {
return () -> { throw errorSupplier.get(); };
}