valores usar retornan referenciados referencia que por metodos expresiones ejercicios ejemplos como java lambda java-8

usar - metodos referenciados java 8



Excepción no controlada de referencia de método Java 8 (4)

Estoy trabajando en un proyecto con Java 8 y encontré una situación que no puedo entender.

Tengo un código como este:

void deleteEntity(Node node) throws SomeException { for (ChildNode child: node.getChildren()) { deleteChild(child); } } void deleteChild(Object child) throws SomeException { //some code }

Este código funciona bien, pero puedo reescribirlo con una referencia de método:

void deleteEntity(Node node) throws SomeException { node.getChildren().forEach(this::deleteChild); }

Y este código no se compila, dando el error Incompatible thrown types *SomeException* in method reference .

También IDEA me dio la unhandled exception error unhandled exception .

¿Mi pregunta es, porque? ¿Por qué el código se compila con cada ciclo y no se compila con lambda?


** Si no desea escribir su propia interfaz de consumidor y hacer uso de ella. Puede usar su Excepción personalizada con facilidad como se muestra a continuación. Puedes actuar como a continuación. ** **

list.stream().forEach(x->{ try{ System.out.println(x/0); }catch(ArithmeticException e){ throw new RuntimeException(new MyCustomException(FirstArgument,SecondArgument)); });


Puedes probar esto:

void deleteEntity(Node node) throws SomeException { node.getChildren().forEach(UtilException.rethrowConsumer(this::deleteChild)); }

La clase auxiliar de UtilException continuación le permite usar cualquier excepción marcada en las secuencias de Java. Tenga en cuenta que la secuencia anterior también arroja la excepción marcada original lanzada por this::deleteChild , y NO alguna excepción de 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; } }

Muchos otros ejemplos sobre cómo usarlo (después de importar estáticamente 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"); }

Pero no lo use antes de comprender las siguientes ventajas, desventajas y limitaciones :

• Si el código de llamada es para manejar la excepción marcada, DEBE agregarlo a la cláusula throws del método que contiene la secuencia. El compilador ya no te obligará a agregarlo, por lo que es más fácil olvidarlo.

• Si el código de llamada ya maneja la excepción marcada, el compilador le recordará que agregue la cláusula throws a la declaración del método que contiene la secuencia (si no lo hace, dirá: la excepción nunca se arroja en el cuerpo de la instrucción try correspondiente )

• En cualquier caso, no podrá rodear la secuencia en sí para detectar la excepción marcada DENTRO del método que contiene la secuencia (si lo intenta, el compilador dirá: La excepción nunca se arroja en el cuerpo de la instrucción de prueba correspondiente).

• Si está llamando a un método que literalmente nunca puede lanzar la excepción que declara, entonces no debe incluir la cláusula throws. Por ejemplo: new String (byteArr, "UTF-8") produce UnsupportedEncodingException, pero la especificación de Java garantiza que UTF-8 esté siempre presente. Aquí, la declaración de tiros es una molestia y cualquier solución para silenciarla con un mínimo repetitivo es bienvenida.

• Si odia las excepciones marcadas y cree que, para empezar, nunca deberían agregarse al lenguaje Java (cada vez más personas piensan de esta manera, y yo NO soy una de ellas), entonces simplemente no agregue la excepción marcada al arroja la cláusula del método que contiene la secuencia. La excepción marcada, entonces, se comportará como una excepción NO marcada.

• Si está implementando una interfaz estricta donde no tiene la opción de agregar una declaración de lanzamiento y, sin embargo, lanzar una excepción es completamente apropiado, entonces envolver una excepción solo para obtener el privilegio de lanzarlo resulta en un stacktrace con excepciones espurias que no aportan información sobre lo que realmente salió mal. Un buen ejemplo es Runnable.run (), que no arroja ninguna excepción marcada. En este caso, puede decidir no agregar la excepción marcada a la cláusula throws del método que contiene la secuencia.

• En cualquier caso, si decide NO agregar (u olvidar agregar) la excepción marcada a la cláusula throws del método que contiene la transmisión, tenga en cuenta estas 2 consecuencias de lanzar excepciones CHECKED:

1) El código de llamada no podrá capturarlo por su nombre (si lo intentas, el compilador dirá: la excepción nunca se arroja en el cuerpo de la instrucción de prueba correspondiente). Burbujeará y probablemente quedará atrapado en el bucle principal del programa por alguna "excepción de captura" o "captura Throwable", que puede ser lo que desee de todos modos.

2) Viola el principio de la menor sorpresa: ya no será suficiente capturar RuntimeException para garantizar la captura de todas las posibles excepciones. Por esta razón, creo que esto no debe hacerse en el código marco, sino solo en el código comercial que usted controla por completo.

En conclusión: creo que las limitaciones aquí no son serias, y la clase UtilException se puede usar sin temor. Sin embargo, ¡depende de ti!


Si observa la interfaz Consumer<T> , no se declara que el método de accept (que es lo que su referencia de método usaría efectivamente) arrojaría ninguna excepción verificada; por lo tanto, no puede usar una referencia de método que se declare que arroja Una excepción marcada. El bucle for mejorado está bien, porque siempre estás en un contexto donde se puede lanzar SomeException .

Potencialmente, podría crear un contenedor que convierta la excepción marcada en una excepción no verificada y la arroje. Alternativamente, puede declarar su propia interfaz funcional con un método accept() que arroje una excepción marcada (probablemente parametrizando la interfaz con esa excepción), y luego escribir su propio método forEach que tome esa interfaz funcional como entrada.


También puede declarar someException para que extienda RuntimeException lugar de Exception . Se compilará el siguiente código de ejemplo:

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); } }

La salida será entonces:

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)

Puede agregar un bloque try/catch alrededor de la instrucción forEach , sin embargo, la ejecución de la instrucción forEach se interrumpirá una vez que se forEach una excepción. En el ejemplo anterior, el elemento "bar" de la lista no se imprimirá. Además, al hacerlo, perderá el rastro de la excepción lanzada en su IDE.