¿La función Java 8 Lambda que arroja una excepción?

470

Sé cómo crear una referencia a un método que tiene un Stringparámetro y devuelve un int, es:

Function<String, Integer>

Sin embargo, esto no funciona si la función arroja una excepción, digamos que se define como:

Integer myMethod(String s) throws IOException

¿Cómo definiría esta referencia?

Triton Man
fuente
1
Relacionado: stackoverflow.com/questions/31637892/…
Marko Topolnik el
44
Toda la solución parece algo así, arrojando excepciones de tiempo de ejecución, creo que no es una buena solución. así que mejor usar java viejo para bucles
Nazeel
55
¿Qué pasa con la biblioteca jool ? cf org.jooq.lambda.Paquete no verificado
chaiyachaiya

Respuestas:

403

Tendrá que hacer uno de los siguientes.

  • Si es su código, defina su propia interfaz funcional que declare la excepción marcada:

    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    y úsalo:

    void foo (CheckedFunction f) { ... }
  • De lo contrario, envuelva Integer myMethod(String s)un método que no declare una excepción marcada:

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    y entonces:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    o:

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };
jason
fuente
77
En realidad, puede extender Consumero Functionsi usa métodos predeterminados, consulte mi respuesta a continuación.
jlb
2
Creo que esto se puede lograr de una sola vez .
Ned Twigg
66
Optimización menor: en lugar de (String t) -> myWrappedMethod(t), la referencia del método this::myWrappedMethodtambién se puede utilizar.
Clashsoft
8
Una forma aún más genérica de hacerlo es definir la función marcada como esta @FunctionalInterface public interface CheckedFunction <T, R, E extiende Exception> {R apply (T t) lanza E; } De esa manera, también puede definir qué excepción está lanzando la función y puede reutilizar la interfaz para cualquier código.
Martin Odhelius
3
Guau. Java es peor de lo que pensaba
user275801
194

En realidad, puede ampliar Consumer(y Functionetc.) con una nueva interfaz que maneja excepciones, ¡utilizando los métodos predeterminados de Java 8 !

Considere esta interfaz (se extiende Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

Entonces, por ejemplo, si tiene una lista:

final List<String> list = Arrays.asList("A", "B", "C");

Si desea consumirlo (por ejemplo, con forEach) con algún código que arroje excepciones, tradicionalmente habría configurado un bloque try / catch:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

Pero con esta nueva interfaz, puede crear una instancia con una expresión lambda y el compilador no se quejará:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

¡O incluso solo para que sea más sucinto !:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

Actualización : Parece que hay una muy buena parte de la biblioteca de servicios de Durian llamada Errores que se puede usar para resolver este problema con mucha más flexibilidad. Por ejemplo, en mi implementación anterior, he definido explícitamente la política de manejo de errores ( System.out...o throw RuntimeException), mientras que los Errores de Durian le permiten aplicar una política sobre la marcha a través de un amplio conjunto de métodos de utilidad. Gracias por compartirlo , @NedTwigg !.

Uso de la muestra:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));
jlb
fuente
14
Entonces tiene un conjunto de interfaces (Función, Consumidor, Proveedor, ...) y un conjunto de políticas para manejar errores (Lanzamiento, System.out.println, ...). Creo que hay una manera de facilitar el uso de cualquier política con cualquier tipo de función, sin tener que copiar y pegar "ThrowingConsumer, ThrowingFunction, etc.".
Ned Twigg
1
algún tiempo después ... decidí usar excepciones no verificadas y no usar interfaces funcionales adicionales o nuevas bibliotecas -> el camino fácil, menos tipeo, entrega más rápida, ¿no es así?
aliopi
1
Aquí hay una versión mejorada que usa un lenguaje de lanzamiento furtivo. No es necesario desenvolver RuntimeException en CheckException.
myui
62

Creo que la Errorsclase de Durian combina muchas de las ventajas de las diversas sugerencias anteriores.

Para incluir a Durian en su proyecto, puede:

Ned Twigg
fuente
O simplemente puede usar RxJava ya que las transmisiones necesitan un manejo inherente de errores y si hay algo en su tubería que arroja una excepción, es muy probable que sea una transmisión observable. Esto tampoco fuerza a Java 8 en los consumidores posteriores de una biblioteca.
Adam Gent
2
Tenga en cuenta que Durian no tiene nuevas versiones desde junio de 2016. No es un show stopper, sino algo a tener en cuenta.
Istvan Devai el
99
Durian mantenedor aquí. Que esta roto Si un usuario encuentra un error o una característica importante que falta, publicaremos una corrección de error rápidamente. La biblioteca es simple, por lo tanto, no hemos tenido ningún informe de errores, por lo que no hemos tenido que publicar ninguna corrección de errores.
Ned Twigg el
28

Esto no es específico de Java 8. Está intentando compilar algo equivalente a:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}
asilias
fuente
15
La pregunta es "¿Cómo definiría esta referencia?" . Esto en realidad no responde la pregunta; solo aclara cuál es el problema.
Dawood ibn Kareem
13

Descargo de responsabilidad: todavía no he usado Java 8, solo he leído sobre él.

Function<String, Integer>no arroja IOException, así que no puedes poner ningún código en eso throws IOException. Si está llamando a un método que espera un Function<String, Integer>, entonces la lambda que pasa a ese método no puede arrojar IOException, punto. Puede escribir una lambda como esta (creo que esta es la sintaxis lambda, no estoy seguro):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

O, si el método al que le está pasando el lambda es uno que usted mismo escribió, puede definir una nueva interfaz funcional y usarla como tipo de parámetro en lugar de Function<String, Integer>:

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}
Adam R. Nelson
fuente
agregue la anotación @FunctionalInterface antes de su interfaz, solo entonces será utilizable para lambdas.
Gangnus
13
@Gangnus: la @FunctionalInterfaceanotación no es necesaria para que sea utilizable para lambdas. Sin embargo, se recomienda para el control de la cordura.
Tanmay Patil
9

Si no le importa usar una lib de terceros ( Vavr ), puede escribir

CheckedFunction1<String, Integer> f = this::myMethod;

También tiene el llamado Try mónada que maneja los errores:

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

Por favor lea más aquí .

Descargo de responsabilidad: soy el creador de Vavr.

Daniel Dietrich
fuente
7

Puedes usar unthrow wrapper

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

o

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);
SeregaLBN
fuente
6

Sin embargo, puede crear su propia FunctionalInterface que se muestra a continuación.

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

luego impleméntelo usando Lambdas o referencias como se muestra a continuación.

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}
JohnnyO
fuente
6

Usted puede.

Extendiendo @marcg 's UtilExceptiony agregando genéricos <E extends Exception>cuando sea necesario: de esta manera, el compilador lo obligará nuevamente a agregar cláusulas de lanzamiento y todo es como si pudiera lanzar excepciones comprobadas de forma nativa en las transmisiones de java 8.

public final class LambdaExceptionUtil {

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

    /**
     * .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) {
                throwActualException(exception);
                return null;
            }
        };
    }

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

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}
PaoloC
fuente
5

Tuve este problema con Class.forName y Class.newInstance dentro de una lambda, así que simplemente hice:

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

Dentro de la lambda, en lugar de llamar a Class.forName ("myClass"). NewInstance () acabo de llamar a uncheckedNewInstanceForName ("myClass")

Sergio
fuente
4

Otra solución usando un contenedor de funciones sería devolver una instancia de un contenedor de su resultado, digamos Éxito, si todo salió bien, ya sea una instancia de, digamos Fallo.

Algunos códigos para aclarar cosas:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

Un caso de uso simple:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());
yohan
fuente
4

Este problema también me ha estado molestando; Por eso he creado este proyecto .

Con ella puedes hacer:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

Hay un total de 39 interfaces definidas por el JDK que tienen dicho Throwingequivalente; esos son todos @FunctionalInterfaces usados ​​en streams (la base Streampero también IntStream, LongStreamyDoubleStream ).

Y a medida que cada uno de ellos extiende su contraparte que no arroja, también puedes usarlos directamente en lambdas:

myStringStream.map(f) // <-- works

El comportamiento predeterminado es que cuando su lambda de lanzamiento arroja una excepción marcada, se ThrownByLambdaExceptionproduce a con la excepción marcada como la causa. Por lo tanto, puede capturar eso y obtener la causa.

Otras características están disponibles también.

fge
fuente
Realmente me gusta la idea, solo deseo que haya hecho que los objetos arrojables sean genéricos como se sugiere aquí: javaspecialists.eu/archive/Issue221.html , por ejemplo: @FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }- de esta manera, el usuario no necesita atrapar Throwable, sino la excepción marcada específica.
Zoltán
@ Zoltán sería un dolor declarar la excepción cada vez; Además, siempre puede usar, digamos, .apply () en lugar de .doApply () y capturar ThrownByLambdaException, tendrá la excepción original como causa (o puede usar rethrow(...).as(MyRuntimeException.class))
fge
Creo que hay (una especie de) forma de evitar esto .
Ned Twigg
@NedTwigg He resuelto esto hace mucho tiempo también; Ahora puedo usar Throwing.runnable()y otros, siempre con capacidades de encadenamiento
fge
¡La funcionalidad de encadenamiento es genial! Mi comentario fue sobre si ThrowingRunnable debería tener la excepción genérica o no. Zoltan preguntó si su biblioteca podría tener el argumento como un parámetro genérico, y usted dijo que sería difícil de usar. Mi enlace fue a algunas líneas de código que muestran una forma de hacer que las excepciones sean genéricas, sin que sea una molestia. A menos que lo lea mal, las excepciones en su biblioteca no son genéricas (lo cual es una opción de diseño razonable, porque no obtiene mucha utilidad al hacerlas genéricas).
Ned Twigg
4

Ya hay muchas respuestas excelentes publicadas aquí. Solo intento resolver el problema con una perspectiva diferente. Son solo mis 2 centavos, corrígeme si me equivoco en alguna parte.

La cláusula Throws en FunctionalInterface no es una buena idea

Creo que esto probablemente no sea una buena idea para forzar lanzamientos IOException debido a las siguientes razones

  • Esto me parece un antipatrón para Stream / Lambda. La idea es que la persona que llama decidirá qué código proporcionar y cómo manejar la excepción. En muchos escenarios, la IOException podría no ser aplicable para el cliente. Por ejemplo, si el cliente obtiene valor de la memoria caché / memoria en lugar de realizar E / S real.

  • Además, el manejo de excepciones en las transmisiones se vuelve realmente horrible. Por ejemplo, aquí se verá mi código si uso su API

               acceptMyMethod(s -> {
                    try {
                        Integer i = doSomeOperation(s);
                        return i;
                    } catch (IOException e) {
                        // try catch block because of throws clause
                        // in functional method, even though doSomeOperation
                        // might not be throwing any exception at all.
                        e.printStackTrace();
                    }
                    return null;
                });

    ¿No es feo? Además, como mencioné en mi primer punto, que el método doSomeOperation puede o no lanzar IOException (dependiendo de la implementación del cliente / llamante), pero debido a la cláusula throws en su método FunctionalInterface, siempre tengo que escribir el trata de atraparlo.

¿Qué hago si realmente sé que esta API arroja IOException

  • Entonces, probablemente estamos confundiendo la interfaz funcional con las interfaces típicas. Si sabe que esta API arrojará IOException, entonces probablemente también conozca algunos comportamientos predeterminados / abstractos. Creo que debería definir una interfaz e implementar su biblioteca (con implementación predeterminada / abstracta) de la siguiente manera

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    }

    Pero, el problema try-catch todavía existe para el cliente. Si uso su API en la transmisión, todavía necesito manejar IOException en el horrible bloque try-catch.

  • Proporcione una API amigable de transmisión predeterminada de la siguiente manera

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    
        default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
            try {
                return Optional.ofNullable(this.myMethod(s));
            } catch (Exception e) {
                if (exceptionConsumer != null) {
                    exceptionConsumer.accept(e);
                } else {
                    e.printStackTrace();
                }
            }
    
            return Optional.empty();
        }
    }

    El método predeterminado toma el objeto del consumidor como argumento, que será responsable de manejar la excepción. Ahora, desde el punto de vista del cliente, el código se verá así

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());

    Bien verdad? Por supuesto, se podría usar logger u otra lógica de manejo en lugar de Exception :: printStackTrace.

  • También puede exponer un método similar a https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- . Lo que significa que puede exponer otro método, que contendrá la excepción de la llamada al método anterior. La desventaja es que ahora está haciendo que sus API tengan estado, lo que significa que necesita manejar la seguridad de subprocesos y que eventualmente se convertirá en un éxito en el rendimiento. Sin embargo, es solo una opción a considerar.

TriCore
fuente
Estoy de acuerdo en que convertir la Excepción marcada en una Excepción no marcada, o tragar la Excepción no es una buena idea porque no hay forma de saber qué elemento de la StreamExcepción planteada. Por lo tanto, me gusta la idea de tener un controlador de excepciones y filtrar los resultados que no son válidos. Tenga en cuenta que su MyAmazingAPI es efectivamente una FunctionalInterface(por lo tanto, puede agregar la anotación @FunctionalInterface). También podría tener un valor predeterminado en lugar de usar Optional.empty().
Julien Kronegg
4

El lenguaje furtivo disimulado permite evitar la CheckedExceptionexpresión de Lambda. Ajustar a CheckedExceptionen a RuntimeExceptionno es bueno para el manejo estricto de errores.

Se puede utilizar como una Consumerfunción utilizada en una colección Java.

Aquí hay una versión simple y mejorada de la respuesta de jib .

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}

Esto simplemente envuelve la lambda en un nuevo lanzamiento . Hace CheckedExceptionvolver a Exceptiontirar cualquiera que haya sido arrojado en tu lambda.

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}

Encuentre un código completo y pruebas unitarias aquí .

myui
fuente
3

Puedes usar ET para esto. ET es una pequeña biblioteca Java 8 para conversión / traducción de excepciones.

Con ET se ve así:

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslatorlas instancias son seguras para subprocesos y pueden ser compartidas por múltiples componentes. Puede configurar reglas de conversión de excepciones más específicas (por ejemplo FooCheckedException -> BarRuntimeException) si lo desea. Si no hay otras reglas disponibles, las excepciones marcadas se convierten automáticamente a RuntimeException.

(Descargo de responsabilidad: soy el autor de ET)

micha
fuente
2
Parece que eres el autor de esta biblioteca. De acuerdo con las reglas de SO , debe divulgar su afiliación en sus respuestas. Agregue explícitamente a su respuesta que escribió esta biblioteca (lo mismo para otras respuestas relacionadas con ET).
Tagir Valeev
2
Hola Tagir, gracias por la pista. Actualicé la respuesta.
micha
2

Lo que estoy haciendo es permitir que el usuario dé el valor que realmente desea en caso de excepción. Así que tengo algo parecido a esto

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}

Y esto se puede llamar así:

defaultIfThrows(child -> child.getID(), null)
mmounirou
fuente
1
Esta es una extensión de esta idea que distingue entre una estrategia de "valor predeterminado" (como en su respuesta) y una estrategia de "volver a lanzar RuntimeException", donde no es necesario un valor predeterminado.
Ned Twigg
2

Si no le importa usar una biblioteca de terceros, con cyclops-react , una biblioteca a la que contribuyo, puede usar la API FluentFunctions para escribir

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);

ofChecked toma una función comprobada jOOλ y devuelve la referencia suavizada a un JDK estándar (sin marcar) java.util.function.Function.

Alternativamente, puede seguir trabajando con la función capturada a través de la API de FluentFunctions.

Por ejemplo, para ejecutar su método, reintentándolo hasta 5 veces y registrando su estado, puede escribir

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");
John McClean
fuente
2

De manera predeterminada, la función Java 8 no permite generar excepciones y, como se sugiere en varias respuestas, hay muchas maneras de lograrlo, una de ellas es:

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

Definir como:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

Y agregue throwso try/catchla misma excepción en el método de llamada.

Arpit Aggarwal
fuente
2

Cree un tipo de devolución personalizado que propague la excepción marcada. Esta es una alternativa a la creación de una nueva interfaz que refleja la interfaz funcional existente con la ligera modificación de una "excepción de lanzamiento" en el método de la interfaz funcional.

Definición

CheckedValueSupplier

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

CheckedValue

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

Uso

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();

¿Que esta pasando?

Se crea una única interfaz funcional que arroja una excepción marcada ( CheckedValueSupplier). Esta será la única interfaz funcional que permite excepciones marcadas. Todas las demás interfaces funcionales aprovecharán CheckedValueSupplierpara envolver cualquier código que arroje una excepción marcada.

La CheckedValueclase mantendrá el resultado de ejecutar cualquier lógica que arroje una excepción marcada. Esto evita la propagación de una excepción marcada hasta el punto en que el código intenta acceder al valor que CheckedValuecontiene una instancia .

Los problemas con este enfoque.

  • Ahora estamos lanzando "Excepción" ocultando efectivamente el tipo específico originalmente lanzado.
  • No sabemos si se produjo una excepción hasta que CheckedValue#get()se llama.

Consumer et al.

Algunas interfaces funcionales (Consumer por ejemplo) deben manejarse de manera diferente ya que no proporcionan un valor de retorno.

Función en lugar del consumidor

Un enfoque es usar una función en lugar de un consumidor, que se aplica cuando se manejan flujos.

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior

Escalar

Alternativamente, siempre puede escalar a a RuntimeException. Hay otras respuestas que cubren la escalada de una excepción marcada desde dentro de a Consumer.

No consumir

Simplemente evite las interfaces funcionales y use un bucle for bien diseñado.

justin.hughey
fuente
2

Utilizo una función de utilidad sobrecargada llamada unchecked()que maneja múltiples casos de uso.


ALGUNOS USOS DE EJEMPLO

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

UTILIDADES DE APOYO

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}
Stephen Paul
fuente
0

Varias de las soluciones ofrecidas utilizan un argumento genérico de E para pasar el tipo de excepción que se produce.

Vaya un paso más allá y, en lugar de pasar el tipo de excepción, pase un Consumidor del tipo de excepción, como en ...

Consumer<E extends Exception>

Puede crear varias variaciones reutilizables Consumer<Exception>que cubrirían las necesidades comunes de manejo de excepciones de su aplicación.

Rodney P. Barbati
fuente
0

Haré algo genérico:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

uso:

 Lambda.handle(() -> method());
ahll
fuente
0

Usar Jool Libraryo decir jOOλ librarydeJOOQ . No solo proporciona interfaces manejadas de excepciones no verificadas, sino que también proporciona a la clase Seq muchos métodos útiles.

Además, contiene interfaces funcionales con hasta 16 parámetros. Además, proporciona la clase Tuple que se usa en diferentes escenarios.

Jool Git Link

Específicamente en la búsqueda de la biblioteca para el org.jooq.lambda.fi.util.functionpaquete. Contiene todas las interfaces de Java-8 con Checked antepuesto. Consulte a continuación para referencia: -

ingrese la descripción de la imagen aquí

Vinay Prajapati
fuente
0

Soy el autor de una pequeña lib con algo de magia genérica para lanzar cualquier Excepción de Java a cualquier lugar sin la necesidad de atraparlas o envolverlasRuntimeException .

Uso: unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

fuente: https://github.com/qoomon/unchecked-exceptions-java

qoomon
fuente
-7
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
Franky Knuckels
fuente
3
¿Te importaría comentar tu trabajo? Las respuestas de solo código no son tan útiles.
Phantômaxx
@Franky puedes arreglar tu presentación usando 4 <code>/<code>
espacios