Related
I was trying to have a handleException method, which can take an exception object and a list of acceptable exception classes to check if the exception is acceptable and can be retried.
void handleException(Exception e, String... acceptableExceptionNames)
throws MyException {
boolean isRetryable = false;
for(String acceptableExceptionName: acceptableExceptionNames) {
try {
if (Class.forName(acceptableExceptionName).isInstance(e)) {
isRetryable = true;
break;
}
} catch (ClassNotFoundException e1) {
continue;
}
}
if (isRetryable) {
// log retryable
} else {
// log error
}
throw new MyException(isRetryable, "Failed");
}
The parameter I pass in is a String... classNames instead of Class<? extends Exception> classes, because if I do something like this:
void handleException(
Exception e,
Class<? extends Exception>... acceptableExceptions)
throws MyException {
for (Class acceptableException : acceptableExceptions) {
if (e instanceOf acceptableException) {}
}
}
The IDE will complain about unknown class acceptableException
Anyone knows if there's a way to pass Class<?>? Or a better way to avoid using String classNames and Class.forName()?
acceptableExceptions isn't a Class, it's a Class[]. You can keep your original design, though, and just use the Class objects directly instead of creating them from strings:
void handleException
(Exception e, Class<? extends Exception>... acceptableExceptionNames)
throws MyException {
boolean isRetryable = false;
for(Class<?> acceptableExceptionName: acceptableExceptionNames) {
if (acceptableExceptionName.isInstance(e)) {
isRetryable = true;
break;
}
}
if (isRetryable) {
// log retryable
} else {
// log error
}
throw new MyException(isRetryable, "Failed");
}
EDIT:
As a side note, this code can be made considerably shorter using Java 8's streams:
void handleException
(Exception e, Class<? extends Exception>... acceptableExceptionNames)
throws MyException {
boolean isRetryable =
Arrays.stream(acceptableExceptionNames).anyMatch(x -> x.isInstance(e));
if (isRetryable) {
// log retryable
} else {
// log error
}
throw new MyException(isRetryable, "Failed");
}
You don't want to check if e is an instance of a Class[], which is what acceptableExceptions is, but if it is an instance of one of the classes referenced by the acceptableExceptions array.
To do that, you need to iterate them, and you need to use the reflection method Class.isInstance(Object obj). As the javadoc says:
This method is the dynamic equivalent of the Java language instanceof operator.
To prevent compiler warnings, you also need to add #SafeVarargs to you method if it is static or final. Otherwise, you need to add #SuppressWarnings("unchecked") to both the method and it's caller(s).
#SuppressWarnings("unchecked")
void handleException(Exception e, Class<? extends Exception>... acceptableExceptions) throws MyException {
boolean acceptable = false;
for (Class<? extends Exception> acceptableException : acceptableExceptions)
if (acceptableException.isInstance(e)) {
acceptable = true;
break;
}
if (acceptable) {
// code here
}
}
In my opinion, it's easier to do if by performing the simple String Comparisons like this:
private void handleException(Exception ex, String... acceptableException) {
for (int x = 0; x < acceptableException.length; x++) {
String[] exceptionClass = ex.getClass().toString().split(".");
if (!acceptableException[x]
.equals(exceptionClass[exceptionClass.length - 1])) {
/* Exception Not Acceptable */
}
}
/* Exception Acceptable */
}
Use following checking
for (Class<? extends Exception> exceptionClass : acceptableExceptions) {
if (exceptionClass.isInstance(e)) {
// it is your exception
}
}
How can I throw CHECKED exceptions from inside Java 8 lambda, used in a stream for example?
In other words, I want to make code like this compile:
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;
}
This code does not compile, since the Class.forName() method above throws ClassNotFoundException, which is checked.
Please note I do NOT want to wrap the checked exception inside a runtime exception and throw the wrapped unchecked exception instead. I want to throw the checked exception itself, and without adding ugly try/catches to the stream.
The simple answer to your question is: You can't, at least not directly. And it's not your fault. Oracle messed it up. They cling on the concept of checked exceptions, but inconsistently forgot to take care of checked exceptions when designing the functional interfaces, streams, lambda etc. That's all grist to the mill of experts like Robert C. Martin who call checked exceptions a failed experiment.
In my opinion, this is a huge bug in the API and a minor bug in the language specification.
The bug in the API is that it provides no facility for forwarding checked exceptions where this actually would make an awful lot of sense for functional programming. As I will demonstrate below, such a facility would've been easily possible.
The bug in the language specification is that it does not allow a type parameter to infer a list of types instead of a single type as long as the type parameter is only used in situations where a list of types is permissable (throws clause).
Our expectation as Java programmers is that the following code should compile:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class CheckedStream {
// List variant to demonstrate what we actually had before refactoring.
public List<Class> getClasses(final List<String> names) throws ClassNotFoundException {
final List<Class> classes = new ArrayList<>();
for (final String name : names)
classes.add(Class.forName(name));
return classes;
}
// The Stream function which we want to compile.
public Stream<Class> getClasses(final Stream<String> names) throws ClassNotFoundException {
return names.map(Class::forName);
}
}
However, it gives:
cher#armor1:~/playground/Java/checkedStream$ javac CheckedStream.java
CheckedStream.java:13: error: incompatible thrown types ClassNotFoundException in method reference
return names.map(Class::forName);
^
1 error
The way in which the functional interfaces are defined currently prevents the Compiler from forwarding the exception - there is no declaration which would tell Stream.map() that if Function.apply() throws E, Stream.map() throws E as well.
What's missing is a declaration of a type parameter for passing through checked exceptions. The following code shows how such a pass-through type parameter actually could have been declared with the current syntax. Except for the special case in the marked line, which is a limit discussed below, this code compiles and behaves as expected.
import java.io.IOException;
interface Function<T, R, E extends Throwable> {
// Declare you throw E, whatever that is.
R apply(T t) throws E;
}
interface Stream<T> {
// Pass through E, whatever mapper defined for E.
<R, E extends Throwable> Stream<R> map(Function<? super T, ? extends R, E> mapper) throws E;
}
class Main {
public static void main(final String... args) throws ClassNotFoundException {
final Stream<String> s = null;
// Works: E is ClassNotFoundException.
s.map(Class::forName);
// Works: E is RuntimeException (probably).
s.map(Main::convertClass);
// Works: E is ClassNotFoundException.
s.map(Main::throwSome);
// Doesn't work: E is Exception.
s.map(Main::throwSomeMore); // error: unreported exception Exception; must be caught or declared to be thrown
}
public static Class convertClass(final String s) {
return Main.class;
}
static class FooException extends ClassNotFoundException {}
static class BarException extends ClassNotFoundException {}
public static Class throwSome(final String s) throws FooException, BarException {
throw new FooException();
}
public static Class throwSomeMore(final String s) throws ClassNotFoundException, IOException {
throw new FooException();
}
}
In the case of throwSomeMore we would like to see IOException being missed, but it actually misses Exception.
This is not perfect because type inference seems to be looking for a single type, even in the case of exceptions. Because the type inference needs a single type, E needs to resolve to a common super of ClassNotFoundException and IOException, which is Exception.
A tweak to the definition of type inference is needed so that the compiler would look for multiple types if the type parameter is used where a list of types is permissible (throws clause). Then the exception type reported by the compiler would be as specific as the original throws declaration of the checked exceptions of the referenced method, not a single catch-all super type.
The bad news is that this means that Oracle messed it up. Certainly they won't break user-land code, but introducing exception type parameters to the existing functional interfaces would break compilation of all user-land code that uses these interfaces explicitly. They'll have to invent some new syntax sugar to fix this.
The even worse news is that this topic was already discussed by Brian Goetz in 2010 (https://blogs.oracle.com/briangoetz/entry/exception_transparency_in_java, http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001484.html) but I'm informed that this investigation ultimately did not pan out, and that there is no current work at Oracle that I know of to mitigate the interactions between checked exceptions and lambdas.
This LambdaExceptionUtil helper class lets you use any checked exceptions in Java streams, like this:
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
Note Class::forName throws ClassNotFoundException, which is checked. The stream itself also throws ClassNotFoundException, and NOT some wrapping unchecked exception.
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; }
}
Many other examples on how to use it (after statically importing 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");
}
UPDATE as of Nov 2015 The code has been improved with the help of #PaoloC, please check his answer below and upvote it. He helped solve the last problem: now the compiler will ask you to add throw clauses and everything is as if you could throw checked exceptions natively on Java 8 streams.
Note 1
The rethrow methods of the LambdaExceptionUtil class above may be used without fear, and are OK to use in any situation.
Note 2
The uncheck methods of the LambdaExceptionUtil class above are bonus methods, and may be safely removed them from the class if you don't want to use them. If you do used them, do it with care, and not before understanding the following use cases, advantages/disadvantages and limitations:
You may use the uncheck methods if you are calling a method which literally can never throw the exception that it declares. For example: new String(byteArr, "UTF-8") throws UnsupportedEncodingException, but UTF-8 is guaranteed by the Java spec to always be present. Here, the throws declaration is a nuisance and any solution to silence it with minimal boilerplate is welcome:
String text = uncheck(() -> new String(byteArr, "UTF-8"));
You may use the uncheck methods if you are implementing a strict interface where you don't have the option for adding a throws declaration, and yet throwing an exception is entirely appropriate. Wrapping an exception just to gain the privilege of throwing it results in a stacktrace with spurious exceptions which contribute no information about what actually went wrong. A good example is Runnable.run(), which does not throw any checked exceptions.
In any case, if you decide to use the uncheck methods, be aware of these two consequences of throwing CHECKED exceptions without a throws clause:
The calling-code won't be able to catch it by name (if you try, the compiler will say: "Exception is never thrown in body of corresponding try statement"). It will bubble and probably be caught in the main program loop by some catch Exception or catch Throwable, which may be what you want anyway.
It violates the principle of least surprise: it will no longer be enough to catch RuntimeException to be able to guarantee catching all possible exceptions. For this reason, I believe this should not be done in framework code, but only in business code that you completely control.
References
http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
http://www.mail-archive.com/javaposse#googlegroups.com/msg05984.html
Project Lombok annotation: #SneakyThrows
Brian Goetz opinion (against) here: How can I throw CHECKED exceptions from inside Java 8 lambdas/streams?
https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *
You can!
Extending #marcg 's UtilException and adding throw E where necessary: this way, the compiler will ask you to add throw clauses and everything's as if you could throw checked exceptions natively on java 8's streams.
Instructions: just copy/paste LambdaExceptionUtil in your IDE and then use it as shown in the below LambdaExceptionUtilTest.
public final class LambdaExceptionUtil {
#FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
#FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
/**
* .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name))));
*/
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) {
throwActualException(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) {
throwActualException(exception);
return null;
}
};
}
#SuppressWarnings("unchecked")
private static <E extends Exception> void throwActualException(Exception exception) throws E {
throw (E) exception;
}
}
Some test to show usage and behaviour:
public class LambdaExceptionUtilTest {
#Test(expected = MyTestException.class)
public void testConsumer() throws MyTestException {
Stream.of((String)null).forEach(rethrowConsumer(s -> checkValue(s)));
}
private void checkValue(String value) throws MyTestException {
if(value==null) {
throw new MyTestException();
}
}
private class MyTestException extends Exception { }
#Test
public void testConsumerRaisingExceptionInTheMiddle() {
MyLongAccumulator accumulator = new MyLongAccumulator();
try {
Stream.of(2L, 3L, 4L, null, 5L).forEach(rethrowConsumer(s -> accumulator.add(s)));
fail();
} catch (MyTestException e) {
assertEquals(9L, accumulator.acc);
}
}
private class MyLongAccumulator {
private long acc = 0;
public void add(Long value) throws MyTestException {
if(value==null) {
throw new MyTestException();
}
acc += value;
}
}
#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();
}
#Test(expected = MyTestException.class)
public void testFunctionRaisingException() throws MyTestException {
Stream.of("ciao", null, "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
}
}
You can't do this safely. You can cheat, but then your program is broken and this will inevitably come back to bite someone (it should be you, but often our cheating blows up on someone else.)
Here's a slightly safer way to do it (but I still don't recommend this.)
class WrappedException extends RuntimeException {
Throwable cause;
WrappedException(Throwable cause) { this.cause = cause; }
}
static WrappedException throwWrapped(Throwable t) {
throw new WrappedException(t);
}
try
source.stream()
.filter(e -> { ... try { ... } catch (IOException e) { throwWrapped(e); } ... })
...
}
catch (WrappedException w) {
throw (IOException) w.cause;
}
Here, what you're doing is catching the exception in the lambda, throwing a signal out of the stream pipeline that indicates that the computation failed exceptionally, catching the signal, and acting on that signal to throw the underlying exception. The key is that you are always catching the synthetic exception, rather than allowing a checked exception to leak out without declaring that exception is thrown.
Just use any one of NoException (my project), jOOλ's Unchecked, throwing-lambdas, Throwable interfaces, or Faux Pas.
// NoException
stream.map(Exceptions.sneak().function(Class::forName));
// jOOλ
stream.map(Unchecked.function(Class::forName));
// throwing-lambdas
stream.map(Throwing.function(Class::forName).sneakyThrow());
// Throwable interfaces
stream.map(FunctionWithThrowable.aFunctionThatUnsafelyThrowsUnchecked(Class::forName));
// Faux Pas
stream.map(FauxPas.throwingFunction(Class::forName));
I wrote a library that extends the Stream API to allow you to throw checked exceptions. It uses Brian Goetz's trick.
Your code would become
public List<Class> getClasses() throws ClassNotFoundException {
Stream<String> classNames =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String");
return ThrowingStream.of(classNames, ClassNotFoundException.class)
.map(Class::forName)
.collect(Collectors.toList());
}
This answer is similar to 17 but avoiding wrapper exception definition:
List test = new ArrayList();
try {
test.forEach(obj -> {
//let say some functionality throws an exception
try {
throw new IOException("test");
}
catch(Exception e) {
throw new RuntimeException(e);
}
});
}
catch (RuntimeException re) {
if(re.getCause() instanceof IOException) {
//do your logic for catching checked
}
else
throw re; // it might be that there is real runtime exception
}
You cannot.
However, you may want to have a look at one of my projects which allows you to more easily manipulate such "throwing lambdas".
In your case, you would be able to do that:
import static com.github.fge.lambdas.functions.Functions.wrap;
final ThrowingFunction<String, Class<?>> f = wrap(Class::forName);
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(f.orThrow(MyException.class))
.collect(Collectors.toList());
and catch MyException.
That is one example. Another example is that you could .orReturn() some default value.
Note that this is STILL a work in progress, more is to come. Better names, more features etc.
TL;DR Just use Lombok's #SneakyThrows.
Christian Hujer has already explained in detail why throwing checked exceptions from a stream is, strictly speaking, not possible due to Java's limitations.
Some other answers have explained tricks to get around the limitations of the language but still being able to fulfil the requirement of throwing "the checked exception itself, and without adding ugly try/catches to the stream", some of them requiring tens of additional lines of boilerplate.
I am going to highlight another option for doing this that IMHO is far cleaner than all the others: Lombok's #SneakyThrows. It has been mentioned in passing by other answers but was a bit buried under a lot of unnecessary detail.
The resulting code is as simple as:
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(className -> getClass(className))
.collect(Collectors.toList());
return classes;
}
#SneakyThrows // <= this is the only new code
private Class<?> getClass(String className) {
return Class.forName(className);
}
We just needed one Extract Method refactoring (done by the IDE) and one additional line for #SneakyThrows. The annotation takes care of adding all the boilerplate to make sure that you can throw your checked exception without wrapping it in a RuntimeException and without needing to declare it explicitly.
Summarizing the comments above the advanced solution is to use a special wrapper for unchecked functions with builder like API which provides recovering, rethrowing and suppresing.
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(Try.<String, Class<?>>safe(Class::forName)
.handle(System.out::println)
.unsafe())
.collect(toList());
Code below demonstrates it for Consumer, Supplier and Function interfaces. It can be easly expanded. Some public keywords were removed for this example.
Class Try is the endpoint for client code. Safe methods may have unique name for each function type.
CheckedConsumer, CheckedSupplier and CheckedFunction are checked analogs of lib functions which can be used independently of Try
CheckedBuilder is the interface for handling exceptions in some checked function. orTry allows execute another same type function if previous was failed. handle provides exception handling including exception type filtering. The order of handlers is important. Reduce methods unsafe and rethrow rethrows last exception in the execution chain. Reduce methods orElse and orElseGet return alternate value like Optional ones if all functions failed. Also there is method suppress. CheckedWrapper is the common implementation of CheckedBuilder.
final class Try {
public static <T> CheckedBuilder<Supplier<T>, CheckedSupplier<T>, T>
safe(CheckedSupplier<T> supplier) {
return new CheckedWrapper<>(supplier,
(current, next, handler, orResult) -> () -> {
try { return current.get(); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().get() : orResult.apply(ex);
}
});
}
public static <T> Supplier<T> unsafe(CheckedSupplier<T> supplier) {
return supplier;
}
public static <T> CheckedBuilder<Consumer<T>, CheckedConsumer<T>, Void>
safe(CheckedConsumer<T> consumer) {
return new CheckedWrapper<>(consumer,
(current, next, handler, orResult) -> t -> {
try { current.accept(t); } catch (Exception ex) {
handler.accept(ex);
if (next.isPresent()) {
next.get().accept(t);
} else {
orResult.apply(ex);
}
}
});
}
public static <T> Consumer<T> unsafe(CheckedConsumer<T> consumer) {
return consumer;
}
public static <T, R> CheckedBuilder<Function<T, R>, CheckedFunction<T, R>, R>
safe(CheckedFunction<T, R> function) {
return new CheckedWrapper<>(function,
(current, next, handler, orResult) -> t -> {
try { return current.applyUnsafe(t); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().apply(t) : orResult.apply(ex);
}
});
}
public static <T, R> Function<T, R> unsafe(CheckedFunction<T, R> function) {
return function;
}
#SuppressWarnings ("unchecked")
static <T, E extends Throwable> T throwAsUnchecked(Throwable exception) throws E {
throw (E) exception;
}
}
#FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
void acceptUnsafe(T t) throws Exception;
#Override default void accept(T t) {
try { acceptUnsafe(t); } catch (Exception ex) {
Try.throwAsUnchecked(ex);
}
}
}
#FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
R applyUnsafe(T t) throws Exception;
#Override default R apply(T t) {
try { return applyUnsafe(t); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
#FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
T getUnsafe() throws Exception;
#Override default T get() {
try { return getUnsafe(); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
interface ReduceFunction<TSafe, TUnsafe, R> {
TSafe wrap(TUnsafe current, Optional<TSafe> next,
Consumer<Throwable> handler, Function<Throwable, R> orResult);
}
interface CheckedBuilder<TSafe, TUnsafe, R> {
CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next);
CheckedBuilder<TSafe, TUnsafe, R> handle(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handle(
Class<E> exceptionType, Consumer<E> handler);
CheckedBuilder<TSafe, TUnsafe, R> handleLast(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Class<E> exceptionType, Consumer<? super E> handler);
TSafe unsafe();
TSafe rethrow(Function<Throwable, Exception> transformer);
TSafe suppress();
TSafe orElse(R value);
TSafe orElseGet(Supplier<R> valueProvider);
}
final class CheckedWrapper<TSafe, TUnsafe, R>
implements CheckedBuilder<TSafe, TUnsafe, R> {
private final TUnsafe function;
private final ReduceFunction<TSafe, TUnsafe, R> reduceFunction;
private final CheckedWrapper<TSafe, TUnsafe, R> root;
private CheckedWrapper<TSafe, TUnsafe, R> next;
private Consumer<Throwable> handlers = ex -> { };
private Consumer<Throwable> lastHandlers = ex -> { };
CheckedWrapper(TUnsafe function,
ReduceFunction<TSafe, TUnsafe, R> reduceFunction) {
this.function = function;
this.reduceFunction = reduceFunction;
this.root = this;
}
private CheckedWrapper(TUnsafe function,
CheckedWrapper<TSafe, TUnsafe, R> prev) {
this.function = function;
this.reduceFunction = prev.reduceFunction;
this.root = prev.root;
prev.next = this;
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next) {
return new CheckedWrapper<>(next, this);
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> handle(
Consumer<Throwable> handler) {
handlers = handlers.andThen(handler);
return this;
}
#Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handle(Class<E> exceptionType, Consumer<E> handler) {
handlers = handlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Consumer<Throwable> handler) {
lastHandlers = lastHandlers.andThen(handler);
return this;
}
#Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handleLast(Class<E> exceptionType, Consumer<? super E> handler) {
lastHandlers = lastHandlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
#Override public TSafe unsafe() {
return root.reduce(ex -> Try.throwAsUnchecked(ex));
}
#Override
public TSafe rethrow(Function<Throwable, Exception> transformer) {
return root.reduce(ex -> Try.throwAsUnchecked(transformer.apply(ex)));
}
#Override public TSafe suppress() {
return root.reduce(ex -> null);
}
#Override public TSafe orElse(R value) {
return root.reduce(ex -> value);
}
#Override public TSafe orElseGet(Supplier<R> valueProvider) {
Objects.requireNonNull(valueProvider);
return root.reduce(ex -> valueProvider.get());
}
private TSafe reduce(Function<Throwable, R> orResult) {
return reduceFunction.wrap(function,
Optional.ofNullable(next).map(p -> p.reduce(orResult)),
this::handle, orResult);
}
private void handle(Throwable ex) {
for (CheckedWrapper<TSafe, TUnsafe, R> current = this;
current != null;
current = current.next) {
current.handlers.accept(ex);
}
lastHandlers.accept(ex);
}
}
Here is a different view or solution for the original problem. Here I show that we have an option to write a code that will process only a valid subset of values with an option to detect and handle caseses when the exception was thrown.
#Test
public void getClasses() {
String[] classNames = {"java.lang.Object", "java.lang.Integer", "java.lang.Foo"};
List<Class> classes =
Stream.of(classNames)
.map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
// log the error
return null;
}
})
.filter(c -> c != null)
.collect(Collectors.toList());
if (classes.size() != classNames.length) {
// add your error handling here if needed or process only the resulting list
System.out.println("Did not process all class names");
}
classes.forEach(System.out::println);
}
Probably, a better and more functional way is to wrap exceptions and propagate them further in the stream. Take a look at the Try type of Vavr for example.
Example:
interface CheckedFunction<I, O> {
O apply(I i) throws Exception; }
static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
return i -> {
try {
return f.apply(i);
} catch(Exception ex) {
throw new RuntimeException(ex);
}
} }
fileNamesToRead.map(unchecked(file -> Files.readAllLines(file)))
OR
#SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwUnchecked(Exception e) throws E {
throw (E) e;
}
static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
return arg -> {
try {
return f.apply(arg);
} catch(Exception ex) {
return throwUnchecked(ex);
}
};
}
2nd implementation avoids wrapping the exception in a RuntimeException. throwUnchecked works because almost always all generic exceptions are treated as unchecked in java.
You can also write a wrapper method to wrap unchecked exceptions, and even enhance wrapper with additional parameter representing another functional interface (with the same return type R).
In this case you can pass a function that would be executed and returned in case of exceptions.
See example below:
private void run() {
List<String> list = Stream.of(1, 2, 3, 4).map(wrapper(i ->
String.valueOf(++i / 0), i -> String.valueOf(++i))).collect(Collectors.toList());
System.out.println(list.toString());
}
private <T, R, E extends Exception> Function<T, R> wrapper(ThrowingFunction<T, R, E> function,
Function<T, R> onException) {
return i -> {
try {
return function.apply(i);
} catch (ArithmeticException e) {
System.out.println("Exception: " + i);
return onException.apply(i);
} catch (Exception e) {
System.out.println("Other: " + i);
return onException.apply(i);
}
};
}
#FunctionalInterface
interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
I agree with the comments above, in using Stream.map you are limited to implementing Function which doesn't throw Exceptions.
You could however create your own FunctionalInterface that throws as below..
#FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
void accept(T instance) throws X;
}
then implement it using Lambdas or references as shown below.
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");
}
}
The only built-in way of handling checked exceptions that can be thrown by a map operation is to encapsulate them within a CompletableFuture. (An Optional is a simpler alternative if you don't need to preserve the exception.) These classes are intended to allow you to represent contingent operations in a functional way.
A couple of non-trivial helper methods are required, but you can arrive at code that's relatively concise, while still making it apparent that your stream's result is contingent on the map operation having completed successfully. Here's what it looks like:
CompletableFuture<List<Class<?>>> classes =
Stream.of("java.lang.String", "java.lang.Integer", "java.lang.Double")
.map(MonadUtils.applyOrDie(Class::forName))
.map(cfc -> cfc.thenApply(Class::getSuperclass))
.collect(MonadUtils.cfCollector(ArrayList::new,
List::add,
(List<Class<?>> l1, List<Class<?>> l2) -> { l1.addAll(l2); return l1; },
x -> x));
classes.thenAccept(System.out::println)
.exceptionally(t -> { System.out.println("unable to get class: " + t); return null; });
This produces the following output:
[class java.lang.Object, class java.lang.Number, class java.lang.Number]
The applyOrDie method takes a Function that throws an exception, and converts it into a Function that returns an already-completed CompletableFuture -- either completed normally with the original function's result, or completed exceptionally with the thrown exception.
The second map operation illustrates that you've now got a Stream<CompletableFuture<T>> instead of just a Stream<T>. CompletableFuture takes care of only executing this operation if the upstream operation succeeded. The API makes this explict, but relatively painless.
Until you get to the collect phase, that is. This is where we require a pretty significant helper method. We want to "lift" a normal collection operation (in this case, toList()) "inside" the CompletableFuture -- cfCollector() lets us do that using a supplier, accumulator, combiner, and finisher that don't need to know anything at all about CompletableFuture.
The helper methods can be found on GitHub in my MonadUtils class, which is very much still a work in progress.
I use this kind of wrapping exception:
public class CheckedExceptionWrapper extends RuntimeException {
...
public <T extends Exception> CheckedExceptionWrapper rethrow() throws T {
throw (T) getCause();
}
}
It will require handling these exceptions statically:
void method() throws IOException, ServletException {
try {
list.stream().forEach(object -> {
...
throw new CheckedExceptionWrapper(e);
...
});
} catch (CheckedExceptionWrapper e){
e.<IOException>rethrow();
e.<ServletExcepion>rethrow();
}
}
Try it online!
Though exception will be anyway re-thrown during first rethrow() call (oh, Java generics...), this way allows to get a strict statical definition of possible exceptions (requires to declare them in throws). And no instanceof or something is needed.
You can do it with apache commons-lang3 library.
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(Failable.asFunction(Class::forName))
.collect(Collectors.toList());
return classes;
}
I think this approach is the right one:
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes;
try {
classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String").map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new UndeclaredThrowableException(e);
}
}).collect(Collectors.toList());
} catch (UndeclaredThrowableException e) {
if (e.getCause() instanceof ClassNotFoundException) {
throw (ClassNotFoundException) e.getCause();
} else {
// this should never happen
throw new IllegalStateException(e.getMessage(), e);
}
}
return classes;
}
Wrapping the checked exception inside the Callable in a UndeclaredThrowableException (that’s the use case for this exception) and unwrapping it outside.
Yes, I find it ugly, and I would advise against using lambdas in this case and just fall back to a good old loop, unless you are working with a parallel stream and paralellization brings an objective benefit that justifies the unreadability of the code.
As many others have pointed out, there are solutions to this situation, and I hope one of them will make it into a future version of Java.
How can I throw CHECKED exceptions from inside Java 8 lambda, used in a stream for example?
In other words, I want to make code like this compile:
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;
}
This code does not compile, since the Class.forName() method above throws ClassNotFoundException, which is checked.
Please note I do NOT want to wrap the checked exception inside a runtime exception and throw the wrapped unchecked exception instead. I want to throw the checked exception itself, and without adding ugly try/catches to the stream.
The simple answer to your question is: You can't, at least not directly. And it's not your fault. Oracle messed it up. They cling on the concept of checked exceptions, but inconsistently forgot to take care of checked exceptions when designing the functional interfaces, streams, lambda etc. That's all grist to the mill of experts like Robert C. Martin who call checked exceptions a failed experiment.
In my opinion, this is a huge bug in the API and a minor bug in the language specification.
The bug in the API is that it provides no facility for forwarding checked exceptions where this actually would make an awful lot of sense for functional programming. As I will demonstrate below, such a facility would've been easily possible.
The bug in the language specification is that it does not allow a type parameter to infer a list of types instead of a single type as long as the type parameter is only used in situations where a list of types is permissable (throws clause).
Our expectation as Java programmers is that the following code should compile:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class CheckedStream {
// List variant to demonstrate what we actually had before refactoring.
public List<Class> getClasses(final List<String> names) throws ClassNotFoundException {
final List<Class> classes = new ArrayList<>();
for (final String name : names)
classes.add(Class.forName(name));
return classes;
}
// The Stream function which we want to compile.
public Stream<Class> getClasses(final Stream<String> names) throws ClassNotFoundException {
return names.map(Class::forName);
}
}
However, it gives:
cher#armor1:~/playground/Java/checkedStream$ javac CheckedStream.java
CheckedStream.java:13: error: incompatible thrown types ClassNotFoundException in method reference
return names.map(Class::forName);
^
1 error
The way in which the functional interfaces are defined currently prevents the Compiler from forwarding the exception - there is no declaration which would tell Stream.map() that if Function.apply() throws E, Stream.map() throws E as well.
What's missing is a declaration of a type parameter for passing through checked exceptions. The following code shows how such a pass-through type parameter actually could have been declared with the current syntax. Except for the special case in the marked line, which is a limit discussed below, this code compiles and behaves as expected.
import java.io.IOException;
interface Function<T, R, E extends Throwable> {
// Declare you throw E, whatever that is.
R apply(T t) throws E;
}
interface Stream<T> {
// Pass through E, whatever mapper defined for E.
<R, E extends Throwable> Stream<R> map(Function<? super T, ? extends R, E> mapper) throws E;
}
class Main {
public static void main(final String... args) throws ClassNotFoundException {
final Stream<String> s = null;
// Works: E is ClassNotFoundException.
s.map(Class::forName);
// Works: E is RuntimeException (probably).
s.map(Main::convertClass);
// Works: E is ClassNotFoundException.
s.map(Main::throwSome);
// Doesn't work: E is Exception.
s.map(Main::throwSomeMore); // error: unreported exception Exception; must be caught or declared to be thrown
}
public static Class convertClass(final String s) {
return Main.class;
}
static class FooException extends ClassNotFoundException {}
static class BarException extends ClassNotFoundException {}
public static Class throwSome(final String s) throws FooException, BarException {
throw new FooException();
}
public static Class throwSomeMore(final String s) throws ClassNotFoundException, IOException {
throw new FooException();
}
}
In the case of throwSomeMore we would like to see IOException being missed, but it actually misses Exception.
This is not perfect because type inference seems to be looking for a single type, even in the case of exceptions. Because the type inference needs a single type, E needs to resolve to a common super of ClassNotFoundException and IOException, which is Exception.
A tweak to the definition of type inference is needed so that the compiler would look for multiple types if the type parameter is used where a list of types is permissible (throws clause). Then the exception type reported by the compiler would be as specific as the original throws declaration of the checked exceptions of the referenced method, not a single catch-all super type.
The bad news is that this means that Oracle messed it up. Certainly they won't break user-land code, but introducing exception type parameters to the existing functional interfaces would break compilation of all user-land code that uses these interfaces explicitly. They'll have to invent some new syntax sugar to fix this.
The even worse news is that this topic was already discussed by Brian Goetz in 2010 (https://blogs.oracle.com/briangoetz/entry/exception_transparency_in_java, http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001484.html) but I'm informed that this investigation ultimately did not pan out, and that there is no current work at Oracle that I know of to mitigate the interactions between checked exceptions and lambdas.
This LambdaExceptionUtil helper class lets you use any checked exceptions in Java streams, like this:
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
Note Class::forName throws ClassNotFoundException, which is checked. The stream itself also throws ClassNotFoundException, and NOT some wrapping unchecked exception.
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; }
}
Many other examples on how to use it (after statically importing 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");
}
UPDATE as of Nov 2015 The code has been improved with the help of #PaoloC, please check his answer below and upvote it. He helped solve the last problem: now the compiler will ask you to add throw clauses and everything is as if you could throw checked exceptions natively on Java 8 streams.
Note 1
The rethrow methods of the LambdaExceptionUtil class above may be used without fear, and are OK to use in any situation.
Note 2
The uncheck methods of the LambdaExceptionUtil class above are bonus methods, and may be safely removed them from the class if you don't want to use them. If you do used them, do it with care, and not before understanding the following use cases, advantages/disadvantages and limitations:
You may use the uncheck methods if you are calling a method which literally can never throw the exception that it declares. For example: new String(byteArr, "UTF-8") throws UnsupportedEncodingException, but UTF-8 is guaranteed by the Java spec to always be present. Here, the throws declaration is a nuisance and any solution to silence it with minimal boilerplate is welcome:
String text = uncheck(() -> new String(byteArr, "UTF-8"));
You may use the uncheck methods if you are implementing a strict interface where you don't have the option for adding a throws declaration, and yet throwing an exception is entirely appropriate. Wrapping an exception just to gain the privilege of throwing it results in a stacktrace with spurious exceptions which contribute no information about what actually went wrong. A good example is Runnable.run(), which does not throw any checked exceptions.
In any case, if you decide to use the uncheck methods, be aware of these two consequences of throwing CHECKED exceptions without a throws clause:
The calling-code won't be able to catch it by name (if you try, the compiler will say: "Exception is never thrown in body of corresponding try statement"). It will bubble and probably be caught in the main program loop by some catch Exception or catch Throwable, which may be what you want anyway.
It violates the principle of least surprise: it will no longer be enough to catch RuntimeException to be able to guarantee catching all possible exceptions. For this reason, I believe this should not be done in framework code, but only in business code that you completely control.
References
http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
http://www.mail-archive.com/javaposse#googlegroups.com/msg05984.html
Project Lombok annotation: #SneakyThrows
Brian Goetz opinion (against) here: How can I throw CHECKED exceptions from inside Java 8 lambdas/streams?
https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *
You can!
Extending #marcg 's UtilException and adding throw E where necessary: this way, the compiler will ask you to add throw clauses and everything's as if you could throw checked exceptions natively on java 8's streams.
Instructions: just copy/paste LambdaExceptionUtil in your IDE and then use it as shown in the below LambdaExceptionUtilTest.
public final class LambdaExceptionUtil {
#FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
#FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
/**
* .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name))));
*/
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) {
throwActualException(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) {
throwActualException(exception);
return null;
}
};
}
#SuppressWarnings("unchecked")
private static <E extends Exception> void throwActualException(Exception exception) throws E {
throw (E) exception;
}
}
Some test to show usage and behaviour:
public class LambdaExceptionUtilTest {
#Test(expected = MyTestException.class)
public void testConsumer() throws MyTestException {
Stream.of((String)null).forEach(rethrowConsumer(s -> checkValue(s)));
}
private void checkValue(String value) throws MyTestException {
if(value==null) {
throw new MyTestException();
}
}
private class MyTestException extends Exception { }
#Test
public void testConsumerRaisingExceptionInTheMiddle() {
MyLongAccumulator accumulator = new MyLongAccumulator();
try {
Stream.of(2L, 3L, 4L, null, 5L).forEach(rethrowConsumer(s -> accumulator.add(s)));
fail();
} catch (MyTestException e) {
assertEquals(9L, accumulator.acc);
}
}
private class MyLongAccumulator {
private long acc = 0;
public void add(Long value) throws MyTestException {
if(value==null) {
throw new MyTestException();
}
acc += value;
}
}
#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();
}
#Test(expected = MyTestException.class)
public void testFunctionRaisingException() throws MyTestException {
Stream.of("ciao", null, "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
}
}
You can't do this safely. You can cheat, but then your program is broken and this will inevitably come back to bite someone (it should be you, but often our cheating blows up on someone else.)
Here's a slightly safer way to do it (but I still don't recommend this.)
class WrappedException extends RuntimeException {
Throwable cause;
WrappedException(Throwable cause) { this.cause = cause; }
}
static WrappedException throwWrapped(Throwable t) {
throw new WrappedException(t);
}
try
source.stream()
.filter(e -> { ... try { ... } catch (IOException e) { throwWrapped(e); } ... })
...
}
catch (WrappedException w) {
throw (IOException) w.cause;
}
Here, what you're doing is catching the exception in the lambda, throwing a signal out of the stream pipeline that indicates that the computation failed exceptionally, catching the signal, and acting on that signal to throw the underlying exception. The key is that you are always catching the synthetic exception, rather than allowing a checked exception to leak out without declaring that exception is thrown.
Just use any one of NoException (my project), jOOλ's Unchecked, throwing-lambdas, Throwable interfaces, or Faux Pas.
// NoException
stream.map(Exceptions.sneak().function(Class::forName));
// jOOλ
stream.map(Unchecked.function(Class::forName));
// throwing-lambdas
stream.map(Throwing.function(Class::forName).sneakyThrow());
// Throwable interfaces
stream.map(FunctionWithThrowable.aFunctionThatUnsafelyThrowsUnchecked(Class::forName));
// Faux Pas
stream.map(FauxPas.throwingFunction(Class::forName));
I wrote a library that extends the Stream API to allow you to throw checked exceptions. It uses Brian Goetz's trick.
Your code would become
public List<Class> getClasses() throws ClassNotFoundException {
Stream<String> classNames =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String");
return ThrowingStream.of(classNames, ClassNotFoundException.class)
.map(Class::forName)
.collect(Collectors.toList());
}
This answer is similar to 17 but avoiding wrapper exception definition:
List test = new ArrayList();
try {
test.forEach(obj -> {
//let say some functionality throws an exception
try {
throw new IOException("test");
}
catch(Exception e) {
throw new RuntimeException(e);
}
});
}
catch (RuntimeException re) {
if(re.getCause() instanceof IOException) {
//do your logic for catching checked
}
else
throw re; // it might be that there is real runtime exception
}
You cannot.
However, you may want to have a look at one of my projects which allows you to more easily manipulate such "throwing lambdas".
In your case, you would be able to do that:
import static com.github.fge.lambdas.functions.Functions.wrap;
final ThrowingFunction<String, Class<?>> f = wrap(Class::forName);
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(f.orThrow(MyException.class))
.collect(Collectors.toList());
and catch MyException.
That is one example. Another example is that you could .orReturn() some default value.
Note that this is STILL a work in progress, more is to come. Better names, more features etc.
TL;DR Just use Lombok's #SneakyThrows.
Christian Hujer has already explained in detail why throwing checked exceptions from a stream is, strictly speaking, not possible due to Java's limitations.
Some other answers have explained tricks to get around the limitations of the language but still being able to fulfil the requirement of throwing "the checked exception itself, and without adding ugly try/catches to the stream", some of them requiring tens of additional lines of boilerplate.
I am going to highlight another option for doing this that IMHO is far cleaner than all the others: Lombok's #SneakyThrows. It has been mentioned in passing by other answers but was a bit buried under a lot of unnecessary detail.
The resulting code is as simple as:
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(className -> getClass(className))
.collect(Collectors.toList());
return classes;
}
#SneakyThrows // <= this is the only new code
private Class<?> getClass(String className) {
return Class.forName(className);
}
We just needed one Extract Method refactoring (done by the IDE) and one additional line for #SneakyThrows. The annotation takes care of adding all the boilerplate to make sure that you can throw your checked exception without wrapping it in a RuntimeException and without needing to declare it explicitly.
Summarizing the comments above the advanced solution is to use a special wrapper for unchecked functions with builder like API which provides recovering, rethrowing and suppresing.
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(Try.<String, Class<?>>safe(Class::forName)
.handle(System.out::println)
.unsafe())
.collect(toList());
Code below demonstrates it for Consumer, Supplier and Function interfaces. It can be easly expanded. Some public keywords were removed for this example.
Class Try is the endpoint for client code. Safe methods may have unique name for each function type.
CheckedConsumer, CheckedSupplier and CheckedFunction are checked analogs of lib functions which can be used independently of Try
CheckedBuilder is the interface for handling exceptions in some checked function. orTry allows execute another same type function if previous was failed. handle provides exception handling including exception type filtering. The order of handlers is important. Reduce methods unsafe and rethrow rethrows last exception in the execution chain. Reduce methods orElse and orElseGet return alternate value like Optional ones if all functions failed. Also there is method suppress. CheckedWrapper is the common implementation of CheckedBuilder.
final class Try {
public static <T> CheckedBuilder<Supplier<T>, CheckedSupplier<T>, T>
safe(CheckedSupplier<T> supplier) {
return new CheckedWrapper<>(supplier,
(current, next, handler, orResult) -> () -> {
try { return current.get(); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().get() : orResult.apply(ex);
}
});
}
public static <T> Supplier<T> unsafe(CheckedSupplier<T> supplier) {
return supplier;
}
public static <T> CheckedBuilder<Consumer<T>, CheckedConsumer<T>, Void>
safe(CheckedConsumer<T> consumer) {
return new CheckedWrapper<>(consumer,
(current, next, handler, orResult) -> t -> {
try { current.accept(t); } catch (Exception ex) {
handler.accept(ex);
if (next.isPresent()) {
next.get().accept(t);
} else {
orResult.apply(ex);
}
}
});
}
public static <T> Consumer<T> unsafe(CheckedConsumer<T> consumer) {
return consumer;
}
public static <T, R> CheckedBuilder<Function<T, R>, CheckedFunction<T, R>, R>
safe(CheckedFunction<T, R> function) {
return new CheckedWrapper<>(function,
(current, next, handler, orResult) -> t -> {
try { return current.applyUnsafe(t); } catch (Exception ex) {
handler.accept(ex);
return next.isPresent() ? next.get().apply(t) : orResult.apply(ex);
}
});
}
public static <T, R> Function<T, R> unsafe(CheckedFunction<T, R> function) {
return function;
}
#SuppressWarnings ("unchecked")
static <T, E extends Throwable> T throwAsUnchecked(Throwable exception) throws E {
throw (E) exception;
}
}
#FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
void acceptUnsafe(T t) throws Exception;
#Override default void accept(T t) {
try { acceptUnsafe(t); } catch (Exception ex) {
Try.throwAsUnchecked(ex);
}
}
}
#FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
R applyUnsafe(T t) throws Exception;
#Override default R apply(T t) {
try { return applyUnsafe(t); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
#FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
T getUnsafe() throws Exception;
#Override default T get() {
try { return getUnsafe(); } catch (Exception ex) {
return Try.throwAsUnchecked(ex);
}
}
}
interface ReduceFunction<TSafe, TUnsafe, R> {
TSafe wrap(TUnsafe current, Optional<TSafe> next,
Consumer<Throwable> handler, Function<Throwable, R> orResult);
}
interface CheckedBuilder<TSafe, TUnsafe, R> {
CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next);
CheckedBuilder<TSafe, TUnsafe, R> handle(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handle(
Class<E> exceptionType, Consumer<E> handler);
CheckedBuilder<TSafe, TUnsafe, R> handleLast(Consumer<Throwable> handler);
<E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Class<E> exceptionType, Consumer<? super E> handler);
TSafe unsafe();
TSafe rethrow(Function<Throwable, Exception> transformer);
TSafe suppress();
TSafe orElse(R value);
TSafe orElseGet(Supplier<R> valueProvider);
}
final class CheckedWrapper<TSafe, TUnsafe, R>
implements CheckedBuilder<TSafe, TUnsafe, R> {
private final TUnsafe function;
private final ReduceFunction<TSafe, TUnsafe, R> reduceFunction;
private final CheckedWrapper<TSafe, TUnsafe, R> root;
private CheckedWrapper<TSafe, TUnsafe, R> next;
private Consumer<Throwable> handlers = ex -> { };
private Consumer<Throwable> lastHandlers = ex -> { };
CheckedWrapper(TUnsafe function,
ReduceFunction<TSafe, TUnsafe, R> reduceFunction) {
this.function = function;
this.reduceFunction = reduceFunction;
this.root = this;
}
private CheckedWrapper(TUnsafe function,
CheckedWrapper<TSafe, TUnsafe, R> prev) {
this.function = function;
this.reduceFunction = prev.reduceFunction;
this.root = prev.root;
prev.next = this;
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next) {
return new CheckedWrapper<>(next, this);
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> handle(
Consumer<Throwable> handler) {
handlers = handlers.andThen(handler);
return this;
}
#Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handle(Class<E> exceptionType, Consumer<E> handler) {
handlers = handlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
#Override public CheckedBuilder<TSafe, TUnsafe, R> handleLast(
Consumer<Throwable> handler) {
lastHandlers = lastHandlers.andThen(handler);
return this;
}
#Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R>
handleLast(Class<E> exceptionType, Consumer<? super E> handler) {
lastHandlers = lastHandlers.andThen(ex -> {
if (exceptionType.isInstance(ex)) {
handler.accept(exceptionType.cast(ex));
}
});
return this;
}
#Override public TSafe unsafe() {
return root.reduce(ex -> Try.throwAsUnchecked(ex));
}
#Override
public TSafe rethrow(Function<Throwable, Exception> transformer) {
return root.reduce(ex -> Try.throwAsUnchecked(transformer.apply(ex)));
}
#Override public TSafe suppress() {
return root.reduce(ex -> null);
}
#Override public TSafe orElse(R value) {
return root.reduce(ex -> value);
}
#Override public TSafe orElseGet(Supplier<R> valueProvider) {
Objects.requireNonNull(valueProvider);
return root.reduce(ex -> valueProvider.get());
}
private TSafe reduce(Function<Throwable, R> orResult) {
return reduceFunction.wrap(function,
Optional.ofNullable(next).map(p -> p.reduce(orResult)),
this::handle, orResult);
}
private void handle(Throwable ex) {
for (CheckedWrapper<TSafe, TUnsafe, R> current = this;
current != null;
current = current.next) {
current.handlers.accept(ex);
}
lastHandlers.accept(ex);
}
}
Here is a different view or solution for the original problem. Here I show that we have an option to write a code that will process only a valid subset of values with an option to detect and handle caseses when the exception was thrown.
#Test
public void getClasses() {
String[] classNames = {"java.lang.Object", "java.lang.Integer", "java.lang.Foo"};
List<Class> classes =
Stream.of(classNames)
.map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
// log the error
return null;
}
})
.filter(c -> c != null)
.collect(Collectors.toList());
if (classes.size() != classNames.length) {
// add your error handling here if needed or process only the resulting list
System.out.println("Did not process all class names");
}
classes.forEach(System.out::println);
}
Probably, a better and more functional way is to wrap exceptions and propagate them further in the stream. Take a look at the Try type of Vavr for example.
Example:
interface CheckedFunction<I, O> {
O apply(I i) throws Exception; }
static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
return i -> {
try {
return f.apply(i);
} catch(Exception ex) {
throw new RuntimeException(ex);
}
} }
fileNamesToRead.map(unchecked(file -> Files.readAllLines(file)))
OR
#SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwUnchecked(Exception e) throws E {
throw (E) e;
}
static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
return arg -> {
try {
return f.apply(arg);
} catch(Exception ex) {
return throwUnchecked(ex);
}
};
}
2nd implementation avoids wrapping the exception in a RuntimeException. throwUnchecked works because almost always all generic exceptions are treated as unchecked in java.
You can also write a wrapper method to wrap unchecked exceptions, and even enhance wrapper with additional parameter representing another functional interface (with the same return type R).
In this case you can pass a function that would be executed and returned in case of exceptions.
See example below:
private void run() {
List<String> list = Stream.of(1, 2, 3, 4).map(wrapper(i ->
String.valueOf(++i / 0), i -> String.valueOf(++i))).collect(Collectors.toList());
System.out.println(list.toString());
}
private <T, R, E extends Exception> Function<T, R> wrapper(ThrowingFunction<T, R, E> function,
Function<T, R> onException) {
return i -> {
try {
return function.apply(i);
} catch (ArithmeticException e) {
System.out.println("Exception: " + i);
return onException.apply(i);
} catch (Exception e) {
System.out.println("Other: " + i);
return onException.apply(i);
}
};
}
#FunctionalInterface
interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
I agree with the comments above, in using Stream.map you are limited to implementing Function which doesn't throw Exceptions.
You could however create your own FunctionalInterface that throws as below..
#FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
void accept(T instance) throws X;
}
then implement it using Lambdas or references as shown below.
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");
}
}
The only built-in way of handling checked exceptions that can be thrown by a map operation is to encapsulate them within a CompletableFuture. (An Optional is a simpler alternative if you don't need to preserve the exception.) These classes are intended to allow you to represent contingent operations in a functional way.
A couple of non-trivial helper methods are required, but you can arrive at code that's relatively concise, while still making it apparent that your stream's result is contingent on the map operation having completed successfully. Here's what it looks like:
CompletableFuture<List<Class<?>>> classes =
Stream.of("java.lang.String", "java.lang.Integer", "java.lang.Double")
.map(MonadUtils.applyOrDie(Class::forName))
.map(cfc -> cfc.thenApply(Class::getSuperclass))
.collect(MonadUtils.cfCollector(ArrayList::new,
List::add,
(List<Class<?>> l1, List<Class<?>> l2) -> { l1.addAll(l2); return l1; },
x -> x));
classes.thenAccept(System.out::println)
.exceptionally(t -> { System.out.println("unable to get class: " + t); return null; });
This produces the following output:
[class java.lang.Object, class java.lang.Number, class java.lang.Number]
The applyOrDie method takes a Function that throws an exception, and converts it into a Function that returns an already-completed CompletableFuture -- either completed normally with the original function's result, or completed exceptionally with the thrown exception.
The second map operation illustrates that you've now got a Stream<CompletableFuture<T>> instead of just a Stream<T>. CompletableFuture takes care of only executing this operation if the upstream operation succeeded. The API makes this explict, but relatively painless.
Until you get to the collect phase, that is. This is where we require a pretty significant helper method. We want to "lift" a normal collection operation (in this case, toList()) "inside" the CompletableFuture -- cfCollector() lets us do that using a supplier, accumulator, combiner, and finisher that don't need to know anything at all about CompletableFuture.
The helper methods can be found on GitHub in my MonadUtils class, which is very much still a work in progress.
I use this kind of wrapping exception:
public class CheckedExceptionWrapper extends RuntimeException {
...
public <T extends Exception> CheckedExceptionWrapper rethrow() throws T {
throw (T) getCause();
}
}
It will require handling these exceptions statically:
void method() throws IOException, ServletException {
try {
list.stream().forEach(object -> {
...
throw new CheckedExceptionWrapper(e);
...
});
} catch (CheckedExceptionWrapper e){
e.<IOException>rethrow();
e.<ServletExcepion>rethrow();
}
}
Try it online!
Though exception will be anyway re-thrown during first rethrow() call (oh, Java generics...), this way allows to get a strict statical definition of possible exceptions (requires to declare them in throws). And no instanceof or something is needed.
You can do it with apache commons-lang3 library.
https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(Failable.asFunction(Class::forName))
.collect(Collectors.toList());
return classes;
}
I think this approach is the right one:
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes;
try {
classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String").map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new UndeclaredThrowableException(e);
}
}).collect(Collectors.toList());
} catch (UndeclaredThrowableException e) {
if (e.getCause() instanceof ClassNotFoundException) {
throw (ClassNotFoundException) e.getCause();
} else {
// this should never happen
throw new IllegalStateException(e.getMessage(), e);
}
}
return classes;
}
Wrapping the checked exception inside the Callable in a UndeclaredThrowableException (that’s the use case for this exception) and unwrapping it outside.
Yes, I find it ugly, and I would advise against using lambdas in this case and just fall back to a good old loop, unless you are working with a parallel stream and paralellization brings an objective benefit that justifies the unreadability of the code.
As many others have pointed out, there are solutions to this situation, and I hope one of them will make it into a future version of Java.
I have a lot of identical classes. I want to improve it using generics:
public class PingInitializer extends AbstractHandler implements DataWarehouseInitializer<PingInteraction, PingInvocation> {
#Handler
#Override
public PingInteraction handle(Message message) throws IOException, MessageException {
checkMessageIsNotNull(message);
PingInvocation invocation = construct(message.getBody().toString());
l.debug("handling in initializer... {}", invocation);
return new PingInteraction(invocation);
}
public PingInvocation construct(String message) throws IOException, MessageException {
ObjectMapper mapper = new ObjectMapper();
PingInvocation invocation;
try {
invocation = mapper.readValue(message, PingInvocation.class);
} catch (IOException e) {
throw new MessageException("Can't deserialize message", e);
}
return invocation;
}
}
I want to create new abstract class AbstractInitializer and all child class just have to specify generic type:
public abstract class AbstractInitializer<INTERACTION, INVOCATION> extends AbstractHandler {
#Handler
public INTERACTION handle(Message message) throws IOException, MessageException {
checkMessageIsNotNull(message);
INVOCATION invocation = construct(message.getBody().toString());
l.debug("handling in initializer... {}", invocation);
return **new INTERACTION(invocation)**; //HERE!
}
public INVOCATION construct(String message) throws IOException, MessageException {
ObjectMapper mapper = new ObjectMapper();
INVOCATION invocation;
try {
invocation = mapper.readValue(message, **INVOCATION.class** /*<- and HERE */);
} catch (IOException e) {
throw new MessageException("Can't deserialize message", e);
}
return invocation;
}
}
But I have two compilers error and don't know how to bypass this issue. I mark them in code
Java generics are implemented with type erasure for compatibility reasons, which ultimately means you cannot use a mere type parameter to instantiate a new object.
What you'll need is to modify AbstractInitializer a bit...
private final Class<INTERACTION> interactionType;
private final Class<INVOCATION> invocationType;
private final Constructor<INTERACTION> interactionConstructor;
public AbstractInitializer(final Class<INTERACTION> interactionType,
final Class<INVOCATION> invocationType) throws NoSuchMethodException {
this.interactionType = interactionType;
this.invocationType = invocationType;
interactionConstructor = interactionType.getConstructor(invocationType);
}
public INTERACTION handle(Message message) throws IOException, MessageException,
InvocationTargetException, InstantiationException, IllegalAccessException {
checkMessageIsNotNull(message);
INVOCATION invocation = construct(message.getBody().toString());
l.debug("handling in initializer... {}", invocation);
return interactionConstructor.newInstance(invocation);
}
public INVOCATION construct(String message) throws IOException, MessageException {
ObjectMapper mapper = new ObjectMapper();
INVOCATION invocation;
try {
invocation = mapper.readValue(message, invocationType);
} catch (IOException e) {
throw new MessageException("Can't deserialize message", e);
}
return invocation;
}
then, as an e.g.
public final class PingInitializer
extends AbstractInitializer<PingInteraction, PingInvocation> {
public PingInitializer() {
super(PingInteraction.class, PingInvocation.class);
}
}
or, you could ditch making it abstract and use it like...
public static GenericInitializer<A, B> createInitializer(final Class<A> a,
final Class<B> b) {
return new GenericInitializer<A, B>(a, b);
}
final GenericInitializer<PingInteraction, PingInvocation> pingInitializer
= createInitializer(PingInteraction.class, PingInvocation.class);
I believe this should all be possible. I probably made some dumb errors, however, given I typed this in the response box in a hurry.
I'm writing a wrapper that calls a method, and if an exception is thrown, logs it and returns a default value.
InvocationHandler invocationHandler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return invokeOn(wrapped, method, args);
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof Exception) {
errorReporter.exception(wrapped, (Exception) targetException);
return defaultValueFor(method.getReturnType());
} else {
throw targetException;
}
}
}
};
I'd like to find a nice way of implementing defaultValueFor so that it returns a good default value for each possible type - the equivalent of
#SuppressWarnings("unchecked")
protected static <T> T defaultValueFor(Class<T> claz) {
if (claz == boolean.class)
return (T) Boolean.FALSE;
if (claz == short.class)
return (T) Short.valueOf((short) 0);
if (claz == int.class)
return (T) Integer.valueOf(0);
if (claz == long.class)
return (T) Long.valueOf(0);
...
return null;
}
This sort of code must be in JMock etc, but is there a nicer implementation than this horrible boiler-plate?
class DefaultValues {
static final Map<Class<?>,Object> defaultValues = new HashMap<Class<?>,Object>();
// load
static {
defaultValues.put(boolean.class, Boolean.FALSE);
defaultValues.put(byte.class, new Byte((byte)0));
defaultValues.put(short.class, new Short((short)0));
defaultValues.put(int.class, new Integer(0));
defaultValues.put(long.class, new Long(0L));
defaultValues.put(char.class, new Character('\0'));
defaultValues.put(float.class, new Float(0.0F));
defaultValues.put(double.class, new Double(0.0));
}
public static final <T> T defaultValueFor(Class<T> clazz) {
return (T)defaultValues.get(clazz);
}
}