是否可以声明 Supplier<T> 需要引发异常?

2022-09-01 02:32:04

所以我正在尝试重构以下代码:

/**
 * Returns the duration from the config file.
 * 
 * @return  The duration.
 */
private Duration durationFromConfig() {
    try {
        return durationFromConfigInner();
    } catch (IOException ex) {
        throw new IllegalStateException("The config file (\"" + configFile + "\") has not been found.");
    }
}

/**
 * Returns the duration from the config file.
 * 
 * Searches the log file for the first line indicating the config entry for this instance.
 * 
 * @return  The duration.
 * @throws FileNotFoundException If the config file has not been found.
 */
private Duration durationFromConfigInner() throws IOException {
    String entryKey = subClass.getSimpleName();
    configLastModified = Files.getLastModifiedTime(configFile);
    String entryValue = ConfigFileUtils.readFileEntry(configFile, entryKey);
    return Duration.of(entryValue);
}

我想出了以下几点开始:

private <T> T getFromConfig(final Supplier<T> supplier) {
    try {
        return supplier.get();
    } catch (IOException ex) {
        throw new IllegalStateException("The config file (\"" + configFile + "\") has not been found.");
    }
}

但是,它不会编译(显然),因为不能抛出.有没有办法将其添加到 的方法声明中?SupplierIOExceptiongetFromConfig

还是像下面这样做的唯一方法?

@FunctionalInterface
public interface SupplierWithIO<T> extends Supplier<T> {
    @Override
    @Deprecated
    default public T get() {
        throw new UnsupportedOperationException();
    }

    public T getWithIO() throws IOException;
}

更新,我刚刚意识到界面是一个非常简单的界面,因为它只有方法。我扩展的最初原因是预先否定基本功能,例如默认方法。Supplierget()Supplier


答案 1
  • 如果你这样做,你将无法使用它,因为它只会抛出不受支持的操作异常。Supplier

  • 考虑到上述情况,为什么不创建一个新接口并在其中声明方法呢?getWithIO

    @FunctionalInterface
    public interface SupplierWithIO<T> {
        public T getWithIO() throws IOException;
    }
    
  • 也许有些东西作为旧式Java接口更好?旧式Java不会仅仅因为现在有Java 8而消失。


答案 2

在 lambda 邮件列表中,对此进行了彻底的讨论。正如你所看到的,Brian Goetz建议另一种选择是编写自己的组合器:

或者你可以写你自己的平凡组合器:

static<T> Block<T> exceptionWrappingBlock(Block<T> b) {
     return e -> {
         try { b.accept(e); }
         catch (Exception e) { throw new RTE(e); }
     };
}

您可以写一次,只需比编写原始电子邮件所花费的时间少。同样,对于您使用的每种SAM,一次。

我宁愿我们把它看作是“玻璃99%满”,而不是替代方案。并非所有问题都需要新的语言功能作为解决方案。(更不用说新的语言功能总是会导致新的问题。

在那些日子里,消费者接口被称为Block。

我认为这与上面Marko提出的JB Nizet的答案相对应。

后来布莱恩解释了为什么这是这样设计的(问题的原因)

是的,您必须提供自己的特殊 SAM。但是,lambda转换将很好地与它们一起工作。

EG讨论了针对此问题的其他语言和库支持,并最终认为这是一个糟糕的成本/收益权衡。

基于库的解决方案导致 SAM 类型(特殊与非)的 2 倍爆炸,这些类型与原始特化的现有组合爆炸交互不良。

可用的基于语言的解决方案是复杂性/价值权衡的输家。虽然有一些替代解决方案,我们将继续探索 - 尽管显然不适合8,也可能不适合9。

与此同时,你有工具去做你想做的事。我知道你更喜欢我们为你提供最后一英里(其次,你的请求实际上是一个薄薄的请求,“你为什么不放弃检查的例外”),但我认为目前的状态可以让你完成工作。


推荐