benjiPosted under c#, Java.

Someone on IRC was asking whether it was possible to do catch multiple types of exceptions at the same time in c#.

In Java 7 there’s a feature from project coin called multi catch that enables the following syntax:

public class MultiCatch {
	public static void main(String... args) {
		try {
			throw new ExceptionA();	
		} catch (final ExceptionA | ExceptionB ex) {
			System.out.println("Got " + ex.getClass().getSimpleName());
		}
	}
}
 
class ExceptionA extends RuntimeException {}
class ExceptionB extends RuntimeException {}

Here the catch block catches either an ExceptionA or an ExceptionB. This can be useful if you want to handle several exceptions in the same way.

I don’t believe c# has a similar language feature, however since it has lambdas you can replicate something similar yourself like so:

using System;
 
public class MultiCatch {
  public static void Main() {
    Trier.Try(() => {
      throw new ExceptionA(" Hello A");
    }).Catch<ExceptionA, ExceptionB>(ex => {
      Console.WriteLine(ex.GetType() + ex.Message);
    });
 
    Trier.Try(() => {
      throw new ExceptionC(" Hello C");
    }).Catch<ExceptionA, ExceptionB, ExceptionC>(ex => {
      Console.WriteLine(ex.GetType() + ex.Message);
    });
  }
}

We create a method called Try and pass it an Action. We then chain a call to a Catch method which we pass the Exceptions we want to catch as Type arguments. As you can see we can vary the number of type arguments. This is something you can’t do in Java partly due to type erasure.

The Try method simply passes the action through to a Catcher

  public static Catcher Try(Action action) {
    return new Catcher(action);
  }

and the Catch method has overloads for any number of exceptions you want to support. We can restrict the type arguments to only Exception types by using the where clause.

  public void Catch<T,U>(Action<Exception> catchAction) where T : Exception where U : Exception {
    try {
      action();
    } catch (T t) {
      catchAction(t);
    } catch (U u) {
      catchAction(u);
    }
  }

Here’s the full code listing:

using System;
 
public class MultiCatch {
  public static void Main() {
    Trier.Try(() => {
      throw new ExceptionA(" Hello A");
    }).Catch<ExceptionA, ExceptionB>(ex => {
      Console.WriteLine(ex.GetType() + ex.Message);
    });
 
    Trier.Try(() => {
      throw new ExceptionC(" Hello C");
    }).Catch<ExceptionA, ExceptionB, ExceptionC>(ex => {
      Console.WriteLine(ex.GetType() + ex.Message);
    });
  }
}
 
class Trier {
  public static Catcher Try(Action action) {
    return new Catcher(action);
  }
}
 
class Catcher {
  private Action action;
  public Catcher(Action action) {
    this.action = action;
  }
 
  public void Catch<T,U>(Action<Exception> catchAction) where T : Exception where U : Exception {
    try {
      action();
    } catch (T t) {
      catchAction(t);
    } catch (U u) {
      catchAction(u);
    }
  }
 
   public void Catch<T,U,V>(Action<Exception> catchAction) where T : Exception where U : Exception where V : Exception {
    try {
      action();
    } catch (T t) {
      catchAction(t);
    } catch (U u) {
      catchAction(u);
    } catch (V v) {
      catchAction(v);
    }
  }
}
 
class ExceptionA : Exception {
  public ExceptionA(string message) : base(message) {}
}
 
class ExceptionB : Exception {
  public ExceptionB(string message) : base(message) {}
}
 
class ExceptionC : Exception {
  public ExceptionC(string message) : base(message) {}
}

This is why Java needs lambdas. Because they fix everything ¬_¬

For reference, the closest I could do in Java prior to 7 was something like this:

public class MultiCatchWithoutCoin {
	public static void main(String... args) {
		new TrierII<ExceptionA, ExceptionB>() {
			public void Try() {
				throw new ExceptionA();
			}
			public void Catch(Exception ex) {
				System.out.println("Got " + ex.getClass().getSimpleName());
			}
		};
	}
}

I had to use an abstract class instead of lambdas as Java has no lambdas. I also had to create a new class for each number of type arguments I wanted because you can’t overload with variable numbers of type arguments.

I also had to use Gafter’s gadget to access the types of the Exceptions to catch.

Here’s the full code listing.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
 
public class MultiCatchWithoutCoin {
	public static void main(String... args) {
		new TrierII<ExceptionA, ExceptionB>() {
			public void Try() {
				throw new ExceptionA();
			}
			public void Catch(Exception ex) {
				System.out.println("Got " + ex.getClass().getSimpleName());
			}
		};
	}
}
 
abstract class TrierII<T extends Exception, U extends Exception> {
	public abstract void Try();
	public abstract void Catch(Exception ex);
	public TrierII() throws T, U {
		try {
			Try();	
		} catch (Exception e) {
			if (getTypeArgument(1).isAssignableFrom(e.getClass()) || getTypeArgument(2).isAssignableFrom(e.getClass())) { 
				Catch(e);
			}
			throw e;
		} 
	}
 
	Class<? extends Exception> getTypeArgument(int num) {
		Type superclass = getClass().getGenericSuperclass();
		if (superclass instanceof Class) {
			throw new RuntimeException("Missing type parameter.");
        	}
        	Type type = ((ParameterizedType) superclass).getActualTypeArguments()[num - 1];
		if (type instanceof Class<?>) {
               		return (Class<? extends Exception>) type;
		} else {
			return (Class<? extends Exception>) ((ParameterizedType) type).getRawType();
		}
	}
 
}
 
class ExceptionA extends RuntimeException {}
class ExceptionB extends RuntimeException {}

Tags:

Leave a Reply

  • (will not be published)