当前位置: 首页 > 面试题库 >

如何从Java 8流中引发CHECKED异常?

澹台庆
2023-03-14
问题内容

如何从Java 8流/ lambda中抛出CHECKED异常?

换句话说,我想使代码像这样编译:

public List<Class> getClasses() throws ClassNotFoundException {     

    List<Class> classes = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
              .map(className -> Class.forName(className))
              .collect(Collectors.toList());                  
    return classes;
    }

由于Class.forName()上面的方法throws ClassNotFoundException,因此该代码无法编译。

请注意,我不想将已检查的异常包装在运行时异常中,而是将已包装的未检查的异常抛出。我想抛出被检查的异常本身,而又不添加丑陋的try/ catches流。


问题答案:

LambdaExceptionUtil帮助程序类使你可以在Java流中使用任何已检查的异常,如下所示:

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

注意Class::forName抛出异常ClassNotFoundException,已被选中。流本身也会抛出ClassNotFoundException,而不是一些包装未检查的异常。

public final class LambdaExceptionUtil {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
    R apply(T t) throws E;
    }

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

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
    return t -> {
        try { return function.apply(t); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }

}

有关如何使用它的许多其他示例(静态导入后LambdaExceptionUtil):

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }   

注意1:可以使用上述类的rethrow方法LambdaExceptionUtil而不必担心,在任何情况下都可以使用。非常感谢帮助解决最后一个问题的用户@PaoloC:现在,编译器将要求你添加throw子句,一切都好像你可以在Java 8流上本地抛出检查异常一样。

注意2:uncheck上述LambdaExceptionUtil类的方法是奖励方法,如果你不想使用它们,可以将其安全地从类中删除。如果你确实使用过它们,请谨慎操作,而不要先了解以下用例,优点/缺点和限制:

uncheck如果要调用一个从字面上永远不会引发其声明的异常的方法,则可以使用这些方法。例如:new String(byteArr,“ UTF-8”)引发UnsupportedEncodingException,但是Java规范保证UTF-8始终存在。在这里,throws声明是个麻烦事,欢迎使用最小的样板来使它静音的任何解决方案:String text = uncheck(() -> new String(byteArr, "UTF-8"));

• uncheck如果要实现一个严格的接口,而该接口没有添加throws声明的选项,但是抛出异常是完全适当的,则可以使用这些方法。包装异常只是为了获得抛出异常的特权,会导致产生带有虚假异常的堆栈跟踪,这些异常不会提供有关实际出了什么问题的信息。一个很好的例子是Runnable.run(),它不会引发任何检查的异常。

•无论如何,如果你决定使用这些uncheck方法,请注意在没有throws子句的情况下抛出CHECKED异常的两种后果:1)调用代码将无法按名称捕获(如果尝试,则编译器会说:永远不会在相应的try语句的主体中引发异常)。它会冒泡,并且可能会被某些“ catch Exception”或“ catch Throwable”捕获在主程序循环中,这可能还是你想要的。2)它违反了最少惊讶的原则:它将不再足以RuntimeException确保能够捕获所有可能的异常。因此,我认为这不应在框架代码中完成,而应在完全控制的业务代码中完成。



 类似资料:
  • 给定一个文件,我们可以使用将其转换为字符串流,例如。, 我们能否以类似的方式从标准输入构建行流?

  • 问题内容: 如何理解java中的checked 和unchecked异常? 问题答案: 许多人说根本不应该使用检查的异常(即应明确捕获或重新抛出的异常)。例如,它们已在C#中被淘汰,并且大多数语言都没有它们。因此,你始终可以抛出RuntimeException(未经检查的异常)的子类 但是,我认为检查异常非常有用-当你要强制API用户考虑如何处理特殊情况(如果可恢复)时,可以使用它们。只是在Jav

  • 问题内容: 在@PostConstruct文档中,它说明了带注释的方法: “该方法绝不能抛出检查异常。” 如何处理例如可以在这种方法中抛出的IOException?只需将其包装在RuntimeException中,然后让用户担心对象的错误初始状态?还是@PostConstruct在错误的地方来验证和初始化已注入依赖项的对象? 问题答案: 是的,将其包装在运行时异常中。最好是更具体的东西。 请注意,

  • 问题内容: 当我尝试使用RaiseError时,出现以下编译问题 消息443,级别16,状态14,过程ConvertSessionToCurr,第19行在函数中无效使用了副作用运算符’RAISERROR’。 那么我们如何处理函数中的异常/将其更改为out参数存储的proc?听起来真是太可惜了! 问题答案: 选项: 返回NULL或一些前哨值 使用存储过程 使其内联代码 我的想法是,如果您在UDF中需

  • 我有两个模块,一个从rest模板调用另一个。(管理员调用notifServer)notifServer有一个用Async注释的方法。我想在该方法中抛出一个异常,但管理员获取响应太快,并且无法在admin中捕获异常方法。 我是spring和@Async进程的新成员。我已经尝试将响应主体从NotifServer映射到C的CompletableFuture。类 。但我仍然没有得到错误响应。 此代码来自管

  • 我有一个包含属性的对象,该属性是包含两个字符串属性的对象列表。我的目标是将此映射的键与另一个包含字符串属性的对象进行比较。 为了更清楚我的请求包含地图: 我的sharePointDriveResponse包含以下列: 在这个阶段,我实现了一些工作正常的东西: 我的问题如下: 在这里传输数据时是否可能引发异常 在示例中:我发送一个创建文档的请求,并传递一个不允许文档使用但允许其他内容类型使用的字段。