Java Tips: Generic Method
Generic is a pretty powerful addition to Java 5. But often people only use generic in the class and forget that generic can also be useful in method. This post will discuss a pretty neat use of generic to avoid casting and reduce duplication.
First, let start with the problem. Say that you have a lot of methods that catch exception and wrapped it with other exception.
public void methodName1() throws AnotherException1 { try { ... } catch (SpecificException1 e) { throw new AnotherException1(e); } } public void methodName2() throws AnotherException2 { try { ... } catch (SpecificException2 e) { throw new AnotherException2(e); } }
Then, customer comes with another requirement that all exceptions should be logged before thrown. Here… the obvious solution is like this:
public void methodName1() throws AnotherException1 { try { ... } catch (SpecificException1 e) { AnotherException1 ex = new AnotherException1(e); log(ex); throw ex; } } public void methodName2() throws AnotherException2 { try { ... } catch (SpecificException2 e) { AnotherException2 ex = new AnotherException2(e); log(ex); throw ex; } }
But that solution is not that elegant because we have to add two lines in every try catch. We can come up with a new method to simplify the change.
public Exception logAndReturnException(Exception e) { log(e); return e; } public void methodName1() throws AnotherException1 { try { ... } catch (SpecificException1 e) { throw (AnotherException1) logAndReturnException(new AnotherException1(e)); } } public void methodName2() throws AnotherException2 { try { ... } catch (SpecificException2 e) { throw (AnotherException2) logAndReturnException(new AnotherException2(e)); } }
That’s remove duplication but not that pretty since we have to add casting in every place. Here, generic can be used to simplify and make our code prettier.
public <E extends Throwable> E logAndReturnException(E e) { log(e); return e; } public void methodName1() throws AnotherException1 { try { ... } catch (SpecificException1 e) { throw logAndReturnException(new AnotherException1(e)); } } public void methodName2() throws AnotherException2 { try { ... } catch (SpecificException2 e) { throw logAndReturnException(new AnotherException2(e)); } }
Pretty neat, right? With the same technique we can simulate lambda calculus or function calling in Java. Try it!