Java 8 메서드 참조 처리되지 않은 예외
Java 8로 프로젝트를 진행 중이며, 수없는 상황을 발견했습니다.
다음과 같은 코드가 있습니다.
void deleteEntity(Node node) throws SomeException {
for (ChildNode child: node.getChildren()) {
deleteChild(child);
}
}
void deleteChild(Object child) throws SomeException {
//some code
}
이 코드는 작동하지만 메서드 참조로 다시 사용할 수 있습니다.
void deleteEntity(Node node) throws SomeException {
node.getChildren().forEach(this::deleteChild);
}
그리고이 코드는 발생하지 않습니다 Incompatible thrown types *SomeException* in method reference
.
또한 IDEA는 나에게 오류를 가지고 unhandled exception
있습니다.
그래서 내 질문은 왜입니까? 코드가 각 루프마다 수행되고 람다로 보이지 않는 이유는 무엇입니까?
이 보면 당신 인터페이스는 그러므로이 방법을 참조 사용할 수 없습니다 - (당신의 방법을 참조 효과적으로 사용하는 것입니다 무엇을 )는 예외를 메소드 확인 던져 선언되지 않은 되는 체크 예외를 던질 선언합니다. for 루프는 괜찮습니다. 항상 왜냐하면 던져 질 수 있는 상황에 있기 때문 입니다.Consumer<T>
accept
SomeException
예외적으로 확인 된 예외를 확인하지 않은 예외로 변환하는 래퍼를 만들 수 있습니다. 또는, 당신은의 당신 자신의 기능 현관적인 인터페이스를 선언 할 수 accept()
방법 않습니다 (아마 제외하고 인터페이스를 매개 변수화) 체크 예외를하고 자신의 쓰기 던져 forEach
입력으로 그 기능 인터페이스를 취 방법.
시도해 볼 수 있습니다.
void deleteEntity(Node node) throws SomeException { node.getChildren().forEach(UtilException.rethrowConsumer(this::deleteChild));
}
UtilException
헬퍼 클래스는 아래의 자바 스트림에서 사용할 수 있습니다. 위의 스트림은 this::deleteChild
래핑 하는 것이 아니라 던진 원래 확인 되지 않는 예외를 던집니다 .
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 절을 추가하도록 알려줍니다 (그렇지 않으면 예외는 해당 try 문의 본문에서 throw되지 않습니다. ).
• 어떤 경우에도 스트림이 포함 된 메서드 내에서 확인 된 예외를 포착하기 위해 스트림 자체를 둘러 쌀 수 없습니다 (시도하면 컴파일러는 다음과 같이 말합니다. 예외는 해당 try 문의 본문에서 throw되지 않습니다).
• 선언 한 예외를 말 그대로 결코 throw 할 수없는 메서드를 호출하는 경우 throws 절을 포함하지 않아야합니다. 예 : new String (byteArr, "UTF-8")은 UnsupportedEncodingException을 발생 시키지만 UTF-8은 Java 스펙에 의해 항상 존재하도록 보장합니다. 여기에서 throws 선언은 성가신 일이며 최소한의 상용구로 침묵하는 모든 솔루션을 환영합니다.
• 확인 된 예외를 싫어하고 시작하기 위해 Java 언어에 추가해서는 안된다고 생각하는 경우 (증가하는 사람들이 이런 식으로 생각하고 저는 그중 하나가 아닙니다), 확인 된 예외를 추가하지 마십시오. 스트림을 포함하는 메서드의 절을 throw합니다. 그러면 확인 된 예외는 확인되지 않은 예외처럼 작동합니다.
• throws 선언을 추가 할 수있는 옵션이없는 엄격한 인터페이스를 구현하고 있지만 예외를 throw하는 것이 전적으로 적절한 경우 예외를 throw하는 권한을 얻기 위해 예외를 래핑하면 가짜 예외가있는 스택 추적이 발생합니다. 실제로 무엇이 잘못되었는지에 대한 정보를 제공하지 않습니다. 확인 된 예외를 발생시키지 않는 Runnable.run ()이 좋은 예입니다. 이 경우 스트림을 포함하는 메서드의 throws 절에 확인 된 예외를 추가하지 않도록 결정할 수 있습니다.
• 어떤 경우 든 스트림이 포함 된 메서드의 throws 절에 확인 된 예외를 추가하지 않기로 결정한 경우 (또는 추가하는 것을 잊은 경우) CHECKED 예외를 throw하는 다음 두 가지 결과에 유의하십시오.
1) 호출 코드는 이름으로 그것을 잡을 수 없습니다 (시도하면 컴파일러는 다음과 같이 말합니다 : 예외는 해당 try 문의 본문에서 throw되지 않습니다). 거품이 발생하고 아마도 "catch Exception"또는 "catch Throwable"에 의해 메인 프로그램 루프에서 잡힐 것입니다.
2) 최소한의 놀라움의 원칙을 위반합니다. 가능한 모든 예외를 잡을 수 있도록 RuntimeException을 잡는 것으로는 더 이상 충분하지 않습니다. 이런 이유로 저는 이것이 프레임 워크 코드가 아니라 완전히 제어하는 비즈니스 코드에서만 이루어져야한다고 생각합니다.
결론 : 여기에있는 한계는 심각하지 않으며, UtilException
수업이 두려움없이 사용될 수 있다고 생각합니다 . 그러나 그것은 당신에게 달려 있습니다!
- 참조 :
- http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
- http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
- 프로젝트 롬복 주석 : @SneakyThrows
- Brian Goetz 의견 (반대) : Java 8 스트림 내부에서 CHECKED 예외를 어떻게 던질 수 있습니까?
- https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *
대신 someException
확장되도록 선언 할 수도 있습니다 . 다음 예제 코드가 컴파일됩니다.RuntimeException
Exception
public class Test {
public static void main(String[] args){
// TODO Auto-generated method stub
List<String> test = new ArrayList<String>();
test.add("foo");
test.add(null);
test.add("bar");
test.forEach(x -> print(x));
}
public static class SomeException extends RuntimeException{
}
public static void print(String s) throws SomeException{
if (s==null) throw new SomeException();
System.out.println(s);
}
}
출력은 다음과 같습니다.
foo
Exception in thread "main" simpleTextLayout.Test$SomeException
at simpleTextLayout.Test.print(Test.java:22)
at simpleTextLayout.Test.lambda$0(Test.java:14)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at simpleTextLayout.Test.main(Test.java:14)
문 try/catch
주위 에 블록을 추가 할 수 forEach
있지만 forEach
예외가 발생 하면 문 실행 이 중단됩니다. 위의 예 "bar"
에서 목록 의 요소는 인쇄되지 않습니다. 또한 그렇게하면 IDE에서 throw 된 예외를 추적 할 수 없게됩니다.
** 자신의 소비자 인터페이스를 작성하고 사용하고 싶지 않은 경우. 아래와 같이 쉽게 Custom Exception을 사용할 수 있습니다. 아래와 같이 수행 할 수 있습니다. **
list.stream().forEach(x->{
try{
System.out.println(x/0);
}catch(ArithmeticException e){
throw new RuntimeException(new MyCustomException(FirstArgument,SecondArgument));
});
참조 URL : https://stackoverflow.com/questions/25643348/java-8-method-reference-unhandled-exception
'ProgramingTip' 카테고리의 다른 글
AngularJs에서 개인 메소드로 테스트 가능한 컨트롤러를 작성하는 방법은 무엇입니까? (0) | 2020.12.25 |
---|---|
node.js에서 하나의 "npm test"명령으로 mocha 및 mocha-phantomjs 테스트를 실행하는 방법은 무엇입니까? (0) | 2020.12.25 |
content_main.xml과 activity_main.xml의 차이점은 무엇입니까? (0) | 2020.12.25 |
Sequel Pro에서 쿼리를 어떻게 실행합니까? (0) | 2020.12.25 |
HTTP 기본 인증을위한 순수 자바 스크립트 코드? (0) | 2020.12.25 |