Java 番石榴的捷径';有例外情况下的可选使用?

Java 番石榴的捷径';有例外情况下的可选使用?,java,guava,Java,Guava,我一直在编写特定的异常抛出器,以防缺少可选项 例如: Optional<?> optional = ...; if (!optional.isPresent()) { throw new MyException(); } Object result = optional.get(); 可选=。。。; 如果(!可选.isPresent()){ 抛出新的MyException(); } 对象结果=可选。get(); 我发现这段代码不是很流畅,尤其是bang(!)的使用。我更喜欢写

我一直在编写特定的异常抛出器,以防缺少可选项

例如:

Optional<?> optional = ...;
if (!optional.isPresent()) {
  throw new MyException();
}
Object result = optional.get();
可选=。。。;
如果(!可选.isPresent()){
抛出新的MyException();
}
对象结果=可选。get();
我发现这段代码不是很流畅,尤其是bang(!)的使用。我更喜欢写这样的东西:

Optional<?> optional = ...;
Object result = optional.orThrow(MyException.class);
可选=。。。;
对象结果=可选的.orThrow(MyException.class);

番石榴有没有我还没有找到的捷径?

我想这不属于图书馆。我发现很难找到一个库,它接收一个异常实例,以便在某些事情没有按预期进行时抛出,特别是因为在许多情况下,异常必须有一条指示出错原因的消息

也就是说,您可以创建自己的可选类来满足您的需要。或者,您可以创建自己的OptionalHelper类,在该类中,您有一个方法可以执行您想要的操作:

public class OptionalHelper {
   public <T> T valueOrThrow(final Optional<T> optional) throws MyException {
      if (optional.isPresent()) {
          return optional.get();
      } else {
          throw new MyException();
      }
   }
}
public类OptionalHelper{
公共T值行(最终可选)抛出MyException{
if(可选的.isPresent()){
返回可选的.get();
}否则{
抛出新的MyException();
}
}
}
编辑:

假设您有一个自定义类,该类接收需要检查的参数/字段名,那么您可以使用一种更好的方法,类似于Premissions所做的:

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);
      }
   }
}
public类OptionalHelper{
公共T值或失败(最终可选,最终字符串字段名)抛出OptionalNotPresentError{
if(可选的.isPresent()){
返回可选的.get();
}否则{
抛出新选项NotPresentError(字段名);
}
}
}

这里有另一种不添加番石榴的方法:

Object result = optional.or(new Supplier() {
    public Object get() {
        throw new MyException();
    }
});
必须取消选中MyException,但这允许您将参数传递给其构造函数。当然,如果你经常这样做,你可以把供应商存放在某个地方,并在你需要的地方使用

Object result = optional.or(SomethingIsMissing.INSTANCE);

作为一名Guava开发人员,让我试着在这里解开逻辑。回答原始问题和直接对该问题的评论:

我们试图迫使Guava用户尊重我们良好编程习惯的标准,这是绝对正确的。(我们的标准受到有效Java等的强烈影响。)

也就是说,我同意你在这个问题中提到的行为有非常好的用例:“如果不存在,抛出一个异常。”也许你正在实现一个可以双向访问的类——一个具有可选返回值的方法,一个假设值始终存在的方法,否则将抛出异常。例如,Deque接口提供了peek、poll和offer的特殊值和异常抛出版本

所有这些,就我所知,真正的番石榴方法是

if (value.isPresent()) {
  return value.get();
} else {
  throw new MyException();
}
您提出的“orThrow”方法需要反射(!!),不允许您使用有用的消息等自定义异常。“普通方法”是完全可读且更有效的

有时候,Guava不提供明确的支持,因为对于那些用例,我们认为最好是以“正常方式”完成。我认为这里就是这样。

这对我来说很有效(没有反射,只是类型推断):


这可能可以进一步扩展,但对于我的用例来说,这已经足够且易于理解了。

Java 8的
可选
具有允许请求行为的
orelsetrow(Supplier)
方法是毫无价值的

它是这样使用的:

Optional<Object> reference = Optional.empty()
reference.orElseThrow(MyOwnException::new); // Throws a new MyOwnException

决定:不-太贵,不是普通图案,可以直接使用!isPresent(),抛出

由于
optional.orThrow(newexception())
不利于性能,因此我更喜欢静态导入,这与

等于

Result result = optional.or(SomeSupplier.throwException());
静态法

public static Supplier<Result> throwException() {
    return new Supplier<Result>() {
        @Override
        public Result get() {
            throw new RuntimeException();
        }

    };
}

派对有点晚了,但这里有一个用番石榴做这件事的优雅例子:

Optional<?> optional = ...;
Object result = optional.or(supplyError(MyException::new));
可选=。。。;
对象结果=可选。或(supplyError(MyException::new));
使用以下帮助器方法:

public static Supplier supplyError(Supplier<Error> errorSupplier) {
    return () -> { throw errorSupplier.get(); };
}
公共静态供应商供应错误(供应商错误供应商){
return()->{throw errorSupplier.get();};
}

一般问题。如果您正在检查的东西是可选的,那么像“Optional.orThrow”这样的方法不符合“Optional”的概念吗?完全同意。如果
isAbsent
(在第11版中添加)是有效条件,则不应导致异常。
Optional
的要点是缺席是一种有效的非例外情况。如果缺席是一个例外情况,您的方法应该只返回对象,并在缺席情况下抛出和异常。@black panda:那么为什么我可以用
或()?这是一种允许默认行为发生的行为,为什么不允许另一种呢?@John B:其中一个用例是一个相当通用的XML属性提取器:该属性可能存在,也可能不存在,因此该方法返回一个
可选的
。然后,调用方可能希望强制该值的存在(通过抛出异常),或者获取该值(如果有的话),甚至检索默认值。提取器方法不知道调用方想对该值做什么,因此它必须返回一个
可选的
。为什么这个用例是无效的?另外,你回答的是我强烈反对的唯一一件事:在我们有限的用例集中完全按照我们的意愿使用,或者干脆离开。这种方法是我在番石榴中看到的唯一缺点——一个很大的缺点,但仍然是唯一的缺点。其余的我都喜欢。我本不希望在这里找到同样的“不”墙。顺便说一句,第11版不包括
isAbsent()
(参见Guava的第734期)@ogregoire:如果某些内容是可选的,那么默认值是可以接受的,这是常见的和预期的行为。这是很自然的
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());
Optional<?> optional = ...;
Object result = optional.or(supplyError(MyException::new));
public static Supplier supplyError(Supplier<Error> errorSupplier) {
    return () -> { throw errorSupplier.get(); };
}