Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I appreciate a lot the new Java 8 features about lambdas and default methods interfaces. Yet, I still get bored with checked exceptions. For instance, if I just want to list all the visible fields of an object I would like to simply write this:

    Arrays.asList(p.getClass().getFields()).forEach(
        f -> System.out.println(f.get(p))
    );

Yet, since the get method might throw a checked exception, which does not agrees with the Consumer interface contract, then I must catch that exception and write the following code:

    Arrays.asList(p.getClass().getFields()).forEach(
            f -> {
                try {
                    System.out.println(f.get(p));
                } catch (IllegalArgumentException | IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                }
            }
    );

However in most cases I just want the exception to be thrown as a RuntimeException and let the program handle, or not, the exception without compilation errors.

So, I would like to have your opinion about my controversial workaround for checked exceptions annoyance. To that end, I created an auxiliary interface ConsumerCheckException<T> and an utility function rethrow (updated according to the sugestion of Doval's comment) as follows:

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

  public class Wrappers {
      public static <T> Consumer<T> rethrow(ConsumerCheckException<T> c) {
        return elem -> {
          try {
            c.accept(elem);
          } catch (Exception ex) {
            /**
             * within sneakyThrow() we cast to the parameterized type T. 
             * In this case that type is RuntimeException. 
             * At runtime, however, the generic types have been erased, so 
             * that there is no T type anymore to cast to, so the cast
             * disappears.
             */
            Wrappers.<RuntimeException>sneakyThrow(ex);
          }
        };
      }

      /**
       * Reinier Zwitserloot who, as far as I know, had the first mention of this
       * technique in 2009 on the java posse mailing list.
       * http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
       */
      public static <T extends Throwable> T sneakyThrow(Throwable t) {
          throw (T) t;
      }
  }

And now I can just write:

    Arrays.asList(p.getClass().getFields()).forEach(
            rethrow(f -> System.out.println(f.get(p)))
    );

I am not sure that this is the best idiom to turn around the checked exceptions, but as I explained, I would like to have a more convenient way of achieving my first example without dealing with checked exceptions and this is the simpler way that I found to do it.

share|improve this question
    
2  
In addition to Robert's link, also take a look at Sneakily Throwing Checked Exceptions. If you wanted to, you could use sneakyThrow inside of rethrow to throw the original, checked exception instead of wrapping it in a RuntimeException. Alternatively you could use the @SneakyThrows annotation from Project Lombok that does the same thing. –  Doval Jan 30 at 4:10
    
Also note that the Consumers in forEach may be executed in parallel fashion when using parallel Streams. A throwable raised from withing the consumer will then propagate to the calling thread, which 1) won't stop the other concurrently running consumers, which may or may not be appropriate, and 2) if more than one of the consumers throw something, only one of the throwables will be seen by the calling thread. –  Joonas Pulakka Feb 5 at 8:10
    

2 Answers 2

In this example, can it ever really fail? Don't think so, but maybe your case is special. If it really "can't fail", and its just an annoying compiler thing, I like to wrap the exception and throw an Error with a comment "cannot happen". Makes things very clear for maintenance. Otherwise they will wonder "how can this happen" and "who the heck handles this?"

This in a controversial practice so YMMV. I'll probably get some downvotes.

share|improve this answer
1  
+1 because you will throw an Error. How many times have I ended up after hours of debugging at a catch block containing just a single line comment "can't happen"... –  Axel Jan 30 at 13:31
    
-1 because you will throw an Error. Errors are to indicate that something is wrong in JVM and upper levels may handle them accordingly. If you choose that way, you should throw RuntimeException. Another possible workarounds are asserts (need -ea flag enabled) or logging. –  duros Mar 28 at 15:31
1  
@duros: Depending upon why the exception "can't happen", the fact that it gets thrown may indicate that something is severely wrong. Suppose, for example, if one calls clone on a sealed type Foo which is known to support it, and it throws CloneNotSupportedException. How could that happen unless the code got linked with some other unexpected kind of Foo? And if that happens, can anything be trusted? –  supercat Jul 9 at 20:46
    
@supercat excellent example. Others are throwing exceptions from missing String Encodings or MessageDigests If UTF-8 or SHA are missing your runtime is likely corrupted. –  user949300 Jul 10 at 0:52

another version of this code where checked exception is just delayed :

public class Cocoon {
         static <T extends Throwable> T forgetThrowsClause(Throwable t) throws T{
            throw (T) t;
        }

        public static <X, T extends Throwable> Consumer<X> consumer(PeskyConsumer<X,T> touchyConsumer) throws T {
            return new Consumer<X>() {
                @Override
                public void accept(X t) {
                    try {
                        touchyConsumer.accept(t);
                    } catch (Throwable exc) {
                        Cocoon.<RuntimeException>forgetThrowsClause(exc) ;
                    }

                }
            } ;
        }
// and so on for Function, and other codes from java.util.function
}

the magic is that if you call:

 myArrayList.forEach(Cocoon.consumer(MyClass::methodThatThrowsException)) ;

then your code will be obliged to catch the exception

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.