Java 是否可以声明供应商<;T>;需要抛出异常吗?

Java 是否可以声明供应商<;T>;需要抛出异常吗?,java,java-8,functional-interface,Java,Java 8,Functional Interface,因此,我尝试重构以下代码: /** * Returns the duration from the config file. * * @return The duration. */ private Duration durationFromConfig() { try { return durationFromConfigInner(); } catch (IOException ex) { throw new IllegalStat

因此,我尝试重构以下代码:

/**
 * 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.");
    }
}
更新,我刚刚意识到
供应商
界面是一个非常简单的界面,因为它只有
get()
方法。我扩展供应商的最初原因是为了优先使用基本功能,例如默认方法。

  • 如果您这样做,您将无法将其用作
    供应商
    ,因为它只会抛出UnsupportedOperationException

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

    @FunctionalInterface
    public interface SupplierWithIO<T> {
        public T getWithIO() throws IOException;
    }
    
    @functioninterface
    带有IO的公共接口供应商{
    public T getWithIO()抛出IOException;
    }
    
  • 也许有些东西比旧式Java接口更好?旧式Java并不是因为现在有了Java8就消失了


我添加了我自己的解决方案,不一定是对我的问题的直接回答,经过一些修改后,它介绍了以下内容:

@FunctionalInterface
public interface CheckedSupplier<T, E extends Exception> {
    public T get() throws E;
}

private <R> R getFromConfig(final String entryKey, final Function<String, R> converter) throws IOException {
    Objects.requireNonNull(entryKey);
    Objects.requireNonNull(converter);
    configLastModified = Files.getLastModifiedTime(configFile);
    return ConfigFileUtils.readFileEntry(configFile, entryKey, converter);
}

private <T> T handleIOException(final CheckedSupplier<T, IOException> supplier) {
    Objects.requireNonNull(supplier);
    try {
        return supplier.get();
    } catch (IOException ex) {
        throw new IllegalStateException("The config file (\"" + configFile + "\") has not been found.");
    }
}
我不太乐意将
IOException
转换为
UncheckedIOException
,如下所示:

  • 我需要为每个可以抛出
    IOException
    的方法添加一个未经检查的变量
  • 我更喜欢明显地处理
    IOException
    ,而不是希望您不要忘记捕获
    未选中的IOException

  • 在lambda邮件列表中,这是一个。正如您所见,Brian Goetz在那里建议,替代方法是编写您自己的combinator:

    static<T> Block<T> exceptionWrappingBlock(Block<T> b) {
         return e -> {
             try { b.accept(e); }
             catch (Exception e) { throw new RTE(e); }
         };
    }
    
    或者您可以编写自己的简单组合器:

    static<T> Block<T> exceptionWrappingBlock(Block<T> b) {
         return e -> {
             try { b.accept(e); }
             catch (Exception e) { throw new RTE(e); }
         };
    }
    
    静态块例外WrappingBlock(块b){
    返回e->{
    试试{b.接受(e);}
    catch(异常e){抛出新的RTE(e);}
    };
    }
    
    你可以写一次,用的时间比写你的文章要少 原始电子邮件。同样,每种SAM使用一次

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

    在那些日子里,消费者界面被称为Block

    我认为这与上面Marko的建议相符

    后来,Brian这样设计(问题的原因)

    是的,您必须提供自己的特殊SAM。但是兰姆达 转换将与他们一起工作

    专家组讨论了这方面的其他语言和库支持 问题,并最终认为这是一个糟糕的成本/效益 权衡

    基于库的解决方案导致SAM类型激增2倍(例外 vs not),它们与现有的组合爆炸产生了严重的交互作用 对于原始专业化

    可用的基于语言的解决方案是来自 复杂性/价值权衡。虽然有一些选择 我们将继续探索解决方案——尽管显然不是 8岁,可能也不是9岁

    同时,你有工具去做你想做的事。我明白了 您希望我们为您提供最后一英里(其次是您的 这个请求实际上是一个隐晦的请求,“你为什么不 已经放弃检查异常),但我认为当前 州政府让你完成工作


    由于我在这个问题上还有一点要说,我决定补充我的答案

    您可以选择编写一个方便的方法,该方法可以是:

  • 将抛出lambda的已检查异常包装为未检查异常
  • 只调用lambda,取消选中异常
  • 在第一种方法中,每个函数方法签名需要一个方便的方法,而在第二种方法中,总共需要两个方法(原语返回方法除外):

    相比

    stream.forEachOrdered(uncheckWrapOneArg(o -> out.write(o)));
    
    我还发现,为所有lambda签名重载包装方法名称通常会导致不明确的lambda表达式错误。因此,您需要更长的不同名称,从而产生比上述方法更长的char-for-char代码

        @FunctionalInterface
        public interface CheckedCall<T, E extends Throwable> {
            T call() throws E;
        }
    
        public <T> T logTime(CheckedCall<T, Exception> block) throws Exception {
    
            Stopwatch timer = Stopwatch.createStarted();
            try {
                T result = block.call();
                System.out.println(timer.stop().elapsed(TimeUnit.MILLISECONDS));
                return result;
            } catch (Exception e) {
                throw e;
            }
        }
    
    
    最后,请注意,上述方法仍然不排除编写简单的包装器方法,这些方法重用
    uncheckedRun/Call
    ,但我发现它很无趣,因为节省最多可以忽略不计。

    Edit

    正如多次指出的,您不需要任何自定义类,而是使用CallableRunnable

    错误、过时的解决方案

    考虑以下通用解决方案:

    // We need to describe supplier which can throw exceptions
    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }
    
    // Now, wrapper
    private <T> T callMethod(ThrowingSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
            return null;
    }
    
    // And usage example
    String methodThrowsException(String a, String b, String c) throws Exception {
        // do something
    }
    
    String result = callMethod(() -> methodThrowsException(x, y, z));
    
    //我们需要描述能够抛出异常的供应商
    @功能接口
    公共接口供应商{
    T get()抛出异常;
    }
    //现在,包装器
    私人呼叫方式(通过供应商){
    试一试{
    返回供应商。get();
    }捕获(例外e){
    抛出新的运行时异常(e);
    }
    返回null;
    }
    //以及使用示例
    String methodThrowsException(字符串a、字符串b、字符串c)引发异常{
    //做点什么
    }
    String result=callMethod(()->methodThrowsException(x,y,z));
    

    我们也可以使用这种通用解决方案。我们用这种方法处理的任何类型的异常

        @FunctionalInterface
        public interface CheckedCall<T, E extends Throwable> {
            T call() throws E;
        }
    
        public <T> T logTime(CheckedCall<T, Exception> block) throws Exception {
    
            Stopwatch timer = Stopwatch.createStarted();
            try {
                T result = block.call();
                System.out.println(timer.stop().elapsed(TimeUnit.MILLISECONDS));
                return result;
            } catch (Exception e) {
                throw e;
            }
        }
    
    
    @functioninterface
    公共接口CheckedCall{
    T call()抛出E;
    }
    公共T日志时间(CheckedCall块)引发异常{
    秒表计时器=Stopwatch.createStarted();
    试一试{
    T result=block.call();
    System.out.println(timer.stop();
    返回结果;
    }捕获(例外e){
    投掷e;
    }
    }
    
    忘记保留选中的异常。。。在中使用
    抛出异常
    签名
    // We need to describe supplier which can throw exceptions
    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }
    
    // Now, wrapper
    private <T> T callMethod(ThrowingSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
            return null;
    }
    
    // And usage example
    String methodThrowsException(String a, String b, String c) throws Exception {
        // do something
    }
    
    String result = callMethod(() -> methodThrowsException(x, y, z));
    
        @FunctionalInterface
        public interface CheckedCall<T, E extends Throwable> {
            T call() throws E;
        }
    
        public <T> T logTime(CheckedCall<T, Exception> block) throws Exception {
    
            Stopwatch timer = Stopwatch.createStarted();
            try {
                T result = block.call();
                System.out.println(timer.stop().elapsed(TimeUnit.MILLISECONDS));
                return result;
            } catch (Exception e) {
                throw e;
            }
        }