2

In Scala, can we add exception throw in a finally block back to the original exception as an suppressed exception?

In Java, if we hit an exception in the try block and then another exception in the finally block, the second exception will be added back to the first exception as a suppressed exception. Therefore, the second exception would not mask the first exception and we still can analyse what happened via checking its suppressed exception.

import java.util.stream.Stream; class Scratch { static class MyCloseable implements AutoCloseable { @Override public void close() throws Exception { throw new Exception("FROM CLOSE METHOD"); } } public static void main(String[] args) { try { try (final MyCloseable closeable = new MyCloseable()){ throw new Exception("From Try Block"); } } catch (Throwable t) { System.out.println(t); Stream.of(t.getSuppressed()).forEach(System.out::println); } } } 

would throw exceptions

  • java.lang.Exception: From Try Block
  • java.lang.Exception: FROM CLOSE METHOD

However, it seems that Scala simply rethrows the second exception (throwing from finally block) and ignore the first exception (throwing from the try block).

try { try { throw new Exception("From Try Block") } finally { throw new Exception("From Final Block") } } catch { case e => e :: e.getSuppressed().toList } 

The above code will simply return only the second exception (thrown from final block). However, I would like to have a way to get both exception.

Anyway to make above code in a better way?

6
  • Checked now in Java 8: try { try { throw new Exception("From Try Block"); } finally { throw new Exception("From Final Block"); } } catch (Throwable t) { System.out.println(t); Stream.of(t.getSuppressed()).forEach(System.out::println); } prints only java.lang.Exception: From Final Block. Commented May 9, 2019 at 17:16
  • 1
    the second exception will be added back to the first exception as a suppressed exception Where do you get this idea? From JLS 14.20.2 (emphasis mine): "If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten)." Commented May 9, 2019 at 17:16
  • 2
    Java's try-with-resources adds suppressed exceptions automatically. Look in this answer stackoverflow.com/questions/39866000/… to see how to implement and abstract it in Scala. Commented May 9, 2019 at 17:19
  • Hi Dmytro Mitin and Silvio Mayolo, Thanks for your comment. I am not referring to the java try-catch-finally block, but the try-with-resources statement. Somehow, they do not work in the same way. Commented May 10, 2019 at 15:30
  • 1
    Hi @Kolmar, Thanks for the link. It looks helpful. Let me check this out. Commented May 10, 2019 at 15:48

1 Answer 1

3

Inasmuch as Scala does not support java's try-with-resources construct, I suppose there is an obvious way to make the code above in a better way = to memorize the first exception:

 try { var te: Option[Throwable] = None try { throw new Exception("From Try Block") } catch { case t: Throwable => te = Some(t) throw t } finally { try { throw new Exception("From Final Block") } catch { case fe: Throwable => throw te.map { e => e.addSuppressed(fe); e }.getOrElse(fe) } } } catch { case e: Throwable => (e :: e.getSuppressed().toList).foreach(println) } 

output:

java.lang.Exception: From Try Block java.lang.Exception: From Final Block 

And below is a nicer way that I would use in the real project:

 def withResources[T <: AutoCloseable, V](r: => T)(f: T => V): V = { val resource: T = r var e: Option[Throwable] = None try f(resource) catch { case t: Throwable => e = Some(t) throw t } finally e.fold(resource.close())(te => try resource.close() catch { case t: Throwable => te.addSuppressed(t) throw te }) } 
 val resource = new AutoCloseable { override def close(): Unit = throw new Exception("From Final Block") } try { withResources(resource)(_ => throw new Exception("From Try Block")) } catch { case e: Throwable => (e :: e.getSuppressed().toList).foreach(println) } 

output:

java.lang.Exception: From Try Block java.lang.Exception: From Final Block 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.