Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should exceptions be case classes?

Should my custom exception types be case classes?

On the plus side, I get extractors.

On the minus side, I get incorrect equality semantics. But I can avoid that by overriding equals.

So does it make sense, at a conceptual level, to make them case classes?

like image 739
missingfaktor Avatar asked Jan 23 '13 12:01

missingfaktor


People also ask

When should you make a new exception class?

You add a new exception class when a user of your API might need to catch it conditionally (or, for checked exceptions specify different, specific types in a throws ).

What will happen if an exception occurs in the base class?

If both base and derived classes are caught as exceptions, then the catch block of the derived class must appear before the base class.

Can a case class extend a case class?

The answer is simple: Case Class can extend another Class, trait or Abstract Class. Create an abstract class which encapsulates the common behavior used by all the classes inheriting the abstract class.

How does JVM handle an exception?

The JVM is responsible for finding an exception handler to process the Exception object. It searches backward through the call stack until it finds a matching exception handler for that particular class of Exception object (in Java term, it is called " catch " the Exception ).


1 Answers

This is very subjective of course, but in my opinion it is good practice to have exception classes as case classes. The main rationale being that when you catch an exception, you are doing pattern matching, and case classes are much nicer to use in pattern matching. Here's an example that takes advantage of the ability to use the full power of pattern matching in a catch block, when using a case class exception:

object IOErrorType extends Enumeration {   val FileNotFound, DeviceError, LockedFile = Value } case class IOError(message: String, errorType: IOErrorType.Value) extends  Exception(message)  def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound)  }  try {   doSomeIO() } catch {   case IOError( msg, IOErrorType.FileNotFound ) =>     println("File not found, please check the path! (" + msg + ")") } 

In this example, we have only one exception, but it contains an errorType field for when you want to know the exact error type that occurred (usually this is modelled through a hierarchy of exception, I'm not saying this is better or worse, the example is just illustrative). Because the IOError is a case class I can simply do case IOError( msg, IOErrorType.FileNotFound ) to catch the exception only for the error type IOErrorType.FileNotFound. Without the extractors that we get for free with case classes, I would have to catch the exception everytime, and then rethrow in case I'm actually not interested, which is definitely more verbose.

You say that case classes give you incorrect equality semantics. I don't think so. You, as the writer of the exception class gets to decides what equality semantics makes sense. After all when you catch an exception, the catch block is where you decide which exceptions to catch usually based on the type alone, but could be based on the value of its fields or whatever, as in my example. The point is that the equality semantics of the exception class has little to do with that.

like image 169
Régis Jean-Gilles Avatar answered Oct 02 '22 11:10

Régis Jean-Gilles