이 UtilException
헬퍼 클래스를 사용하면 다음과 같이 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 UtilException {
@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; }
}
사용 방법에 대한 다른 많은 예제 (정적으로 가져온 후 UtilException
) :
@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");
}
그러나 다음과 같은 장점, 단점 및 제한 사항을 이해하기 전에 사용하지 마십시오 .
• 호출 코드가 확인 된 예외를 처리하는 경우 스트림을 포함하는 메소드의 throws 절에 예외를 추가해야합니다. 컴파일러는 더 이상 강제로 추가하지 않으므로 잊어 버리기가 더 쉽습니다.
• 호출 코드가 이미 확인 된 예외를 처리하는 경우 컴파일러는 스트림을 포함하는 메소드 선언에 throws 절을 추가하도록 알려줍니다 (그렇지 않은 경우 : 해당 try 문의 본문에 예외가 발생하지 않습니다). ).
• 어떤 경우에도 스트림을 포함하는 메서드 내부에서 확인 된 예외를 포착하기 위해 스트림 자체를 둘러 쌀 수 없습니다 (시도하면 컴파일러는 다음과 같이 말합니다. 해당 try 문의 본문에는 예외가 발생하지 않습니다).
• 선언 된 예외를 문자 그대로 던질 수없는 메서드를 호출하는 경우 throws 절을 포함하지 않아야합니다. 예를 들어, new String (byteArr, "UTF-8")은 UnsupportedEncodingException을 발생 시키지만 Java 스펙에서는 UTF-8이 항상 존재하도록 보장합니다. 던지기 선언은 성가신 일이며 최소한의 상용구로 침묵시키는 해결책은 환영합니다.
• 확인 된 예외를 증오하고 처음으로 Java 언어에 추가해서는 안된다고 생각하는 경우 (많은 사람들이 이런 식으로 생각하며 그 중 하나가 아닙니다), 확인 된 예외를 추가하지 마십시오. 스트림을 포함하는 메소드의 절을 던집니다. 그런 다음 확인 된 예외는 확인되지 않은 예외처럼 작동합니다.
• throws 선언을 추가 할 수있는 옵션이없는 엄격한 인터페이스를 구현하고 있지만 예외를 throw하는 것이 전적으로 적합한 경우 예외를 래핑하는 권한을 얻기 위해 예외를 래핑하면 가짜 예외가있는 스택 추적이 발생합니다. 실제로 무엇이 잘못되었는지에 대한 정보를 제공하지 않습니다. 확인 된 예외를 발생시키지 않는 Runnable.run ()이 좋은 예입니다. 이 경우, 점검 된 예외를 스트림을 포함하는 메소드의 throws 절에 추가하지 않기로 결정할 수 있습니다.
• 어떤 경우에도 스트림을 포함하는 메소드의 throws 절에 확인 된 예외를 추가하지 않거나 추가하는 것을 잊은 경우 CHECKED 예외가 발생하는 다음 두 가지 결과에 유의하십시오.
1) 호출 코드는 이름으로 붙잡을 수 없습니다 (시도하면 컴파일러는 다음과 같이 말합니다 : 해당 try 문 본문에는 예외가 발생하지 않습니다). 그것은 아마도 "캐치 예외"또는 "캐치 던지기 가능"에 의해 메인 프로그램 루프에서 잡히고 어쩌면 원하는 것일 수도 있습니다.
2) 최소한의 놀라움의 원칙을 위반합니다. 더 이상 RuntimeException을 포착하여 가능한 모든 예외를 포착 할 수있을만큼 충분하지 않습니다. 따라서 프레임 워크 코드에서는 수행하지 말고 완전히 제어하는 비즈니스 코드에서만 수행해야한다고 생각합니다.
결론 : 나는 여기의 한계가 심각하지 않다고 생각하며 UtilException
클래스는 두려움없이 사용될 수 있습니다. 그러나 그것은 당신에게 달려 있습니다!