java - 使用重新抛出异常的异常处理程序是否有任何明显的区别

标签 java exception optimization

给定一个可能会抛出异常的函数:

public static int f() throws Exception {
    // do something
}

这段代码有什么办法吗:

public static int catchF() throws Exception {
    try {
        return f();
    } catch (Exception ex) {
        throw ex;
    }
}

与直接调用f有什么不同吗? IE。调用者可以通过检查异常来检测差异吗?使用 catchF 而不是 f 是否有任何明显的开销?

如果没有区别,编译器或 JVM 能否将对 catchF 的调用优化为对 f 的直接调用?

虽然这看起来像是一件奇怪的事情,但用例是在之前隐藏异常之后在类型级别重新引入异常:

class Test {

    // Hide the exception.
    public static <X extends Exception, T> T throwUnchecked(Exception ex) throws X {
        throw (X) ex;
    }

    // Interface for functions which throw.
    interface Throws<T, R, X extends Exception> {
        R apply(T t) throws X;
    }


    // Convert a function which throws a visible exception into one that throws a hidden exception.
    public static <T, R, X extends Exception> Function<T, R> wrap(Throws<T, R, X> thrower) {
        return t -> {
            try {
                return thrower.apply(t);
            } catch(Exception ex) {
                return throwUnchecked(ex);
            }
        };
    }

    // Unhide an exception.
    public static <R, X extends Exception> R unwrap(Supplier<R> supp) throws X {
        try {
            return supp.get();
        } catch (Exception ex) {
            throw (X)ex;
        }
    }

    public static Stream<Integer> test(Stream<String> ss) throws NumberFormatException {
        return Test.<Stream<Integer>, NumberFormatException>unwrap(
                () -> ss.map(wrap(Integer::parseInt))
        );
    }

    public static void main(String[] args) throws NumberFormatException {
        final List<Integer> li = test(Arrays.stream(new String[]{"1", "2", "3"})).collect(toList());
        System.out.println(li);
    }
}

目的是将抛出异常的函数包装到在类型级别隐藏异常的函数中。这使得异常可以用于流等情况。

最佳答案

is any different to calling f directly?

没有。

I.e. could the caller detect the difference by inspecting the exception?

不,因为此时您没有构建新的异常。堆栈跟踪是在调用 new WhateverException(...) 的位置构建的(不是throw 所在的位置,尽管它们是通常在同一个地方)。

通常,如果您需要因异常而进行一些清理,则可以重新抛出捕获的异常:

try {
  // ...
} catch (SomeException e) {
  // Clean up resources.
  throw e;
}

调用堆栈展开时发生的事情对于调用者来说既不可见也不相关。

快速演示可以显示,无论异常是 caught and rethrown,堆栈跟踪都是相同的。或者简单地 allowed to propagate .

Is there any discernible overhead in using catchF instead of f?

构造异常的开销将远远超过此冗余构造的任何开销。

关于java - 使用重新抛出异常的异常处理程序是否有任何明显的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57353781/

相关文章:

java - 运行方法两次

java - 如何使用 Guice 注入(inject) Google App Engine 数据存储?

java - 看不懂CYK算法伪代码

javascript - (看似)类中函数的冗余命名

javascript - C++逻辑表达式优化

java - 如何创建一个 java 应用程序来读取 twitter 提要?

java - 可以抛出运行时异常?

java - 从 hadoop unix 运行时增加 jvm 堆空间

c - 访问冲突,读取指针数组时出现未处理的异常

c - 在 8 位中编码 3 个 base-6 数字以提高解包性能