Home of The JavaSpecialists' Newsletter

017aSwitching on Object Handles

Posted: 2001-04-26Category: LanguageJava Version: Dr. Heinz M. Kabutz



Welcome to the 17th issue of The Java(tm) Specialists' Newsletter, after a few very busy days in the Mauritian Paradise. Mauritius is a wonderful place to go to, with extremely friendly people all around, treating you like kings even in business. It's definitely worth a vacation, I wish I had gotten one while I was there ;-)

Please remember to forward this newsletter to anyone who might be interested, friends and foe.

NEW: Refactoring to Java 8 Lambdas and Streams Workshop Are you currently using Java 6 or 7 and would like to see how Java 8 can improve your code base? Are you tired of courses that teach you a whole bunch of techniques that you cannot apply in your world? Check out our one day intensive Refactoring to Java 8 Lambdas and Streams Workshop.

Simulating Switch Statements on Handles with try-catch

This week I will talk about a really completely useless idea, how to use switch/case statements on type-safe constants in Java. This idea occurred to me while I was talking to a bunch of programmers about TCP/IP programming, I don't think my topic of conversation had anything to do with the hare-brained idea presented in this newsletter. My listeners saw my eyes take on a distant gaze and I muttered "hmmm, I wonder if..." so here you go.

First I need to bore you with a monologe of why switch statements are bad and why you should never use them. Switch statements herald from a time before we used Object Orientation, Encapsulation and Polymorphism, and were mostly used to write methods which would do different things depending on the type of record we had passed the method. For example, say we had a CAD system, with a triangle, rectangle and circle, we could say:

public interface Constants {
  int CIRCLE_SHAPE = 2;

Without encapsulation, we would then have a struct or class without methods, looking like this:

public class Shape {
  public int type;
  public java.awt.Color color;

We would then have a CAD system for drawing these shapes, such as

public class CADSystem implements Constants {
  public void draw(Shape shape) {
    switch(shape.type) {
      case TRIANGLE_SHAPE: // some code which draws a triangle
        System.out.println("Triangle with color " + shape.color);
      case RECTANGLE_SHAPE: // some code which draws a rectangle
        System.out.println("Rectangle with color " +shape.color);
      case CIRCLE_SHAPE: // some code which draws a circle
        System.out.println("Circle with color " + shape.color);
      default: // error only found at runtime
        throw new IllegalArgumentException(
          "Shape has illegal type " + shape.type);

This was the old procedural way of writing such code. The result was code where it was extremely challenging to add new types. In addition, in Java such code is very dangerous because we don't have enumerated types and you cannot switch on object references (well, have a look further down on how you actually "can"). You therefore could not be sure at compile time if you had defined the method for all the various types in your CADSystem.

The answer in OO is to use inheritance, polymorphism and encapsulation, the above example would thus be written as:

public abstract class Shape {
  private final java.awt.Color color;
  protected Shape(java.awt.Color color) { this.color = color; }
  public java.awt.Color getColor() { return color; }
  public abstract void draw();

public class Triangle extends Shape {
  public Triangle(java.awt.Color color) { super(color); }
  public void draw() {
    System.out.println("Triangle with color " + getColor());

public class Rectangle extends Shape {
  public Rectangle(java.awt.Color color) { super(color); }
  public void draw() {
    System.out.println("Rectangle with color " + getColor());

public class Circle extends Shape {
  public Circle(java.awt.Color color) { super(color); }
  public void draw() {
    System.out.println("Circle with color " + getColor());

public class CADSystem {
  public void draw(Shape shape) {

Now if we forget to implement one of the draw methods, we'll immediately get a compile-time error. Of course, if we extend Rectangle and forget to implement the draw method we'll get the wrong shape, so a certain level of diligence in testing is still required.

It is possible to take a switch statements and transform it to polymorphism using various refactorings. In previous newsletters I mentioned the book "Refactoring" by Martin Fowler. In case you hadn't noticed, I am a fan (of the book, that is). In that book you can find refactorings to transform a switch/case statement to polymorphism or polymorphism back to a switch/case statement.

So, in the unfortunate case (haha, pun intended) that you want to use a switch-type of construct but you don't want to worry about the anonymity of using int's as type identifiers, how do you do it?

We demonstrate by using a TransactionType class which defines the transaction isolation levels you find in most enterprise systems. The isolation types are None, Read Uncommitted, Read Committed, Repeatable Read and Serializable. The point of this newsletter is not to describe transaction isolations, so I won't go into what they all mean. Rumour has it though, that if you use them without knowing what they mean, you will get a system which doesn't work, HA.

We define a TransactionType superclass with a private constructor, so that it is not possible to construct instances of these types or to subclass it, except from within the type. The constructor takes a name as a description, which can be returned via the toString() method. The reason why the type class has to be Throwable will become clear in the example.

We then make public static inner classes for each of the types, again with private constructors, and make public static final instances of these types in each of the inner classes. The reason why we need classes and instances will also become clearer in the example.

//: TransactionType.java
public class TransactionType extends Throwable {
private final String name;
private TransactionType(String name) {
  this.name = name;
public String toString() { return name; }
public static class None extends TransactionType {
  public static final TransactionType type = new None();
  private None() { super("None"); }
public static class ReadUncommitted extends TransactionType {
  public static final TransactionType type =
    new ReadUncommitted();
  private ReadUncommitted() { super("ReadUncommitted"); }
public static class ReadCommitted extends TransactionType {
  public static final TransactionType type =
    new ReadCommitted();
  private ReadCommitted() { super("ReadCommitted"); }
public static class RepeatableRead extends TransactionType {
  public static final TransactionType type =
    new RepeatableRead();
  private RepeatableRead() { super("RepeatableRead"); }
public static class Serializable extends TransactionType {
  public static final TransactionType type =
    new Serializable();
  private Serializable() { super("Serializable"); }

How does such a type help us to make safe types which we can switch on? The answer is that we use a construct which is not really meant to be used as a switch, but which acts as one nevertheless, namely the throw-catch construct. We simply throw the type, which can be a handle to a TransactionType object, and the exception handling mechanism sorts out which catch to call. Yes, I can hear you all groaning now with pearls of sweat caused by fear, but this really does work. For syntactic sugar, we can import the inner classes using "import TransactionType.*" after which we can refer to the inner class simply by their name "ReadCommitted". We can of course also use the full name such as Transaction.None instead of importing the inner classes.

//: SwitchingOnObjects.java
import TransactionType.*;
public class SwitchingOnObjects {
  public static void switchStatement(TransactionType transact) {
    try {
      throw transact;
    } catch(TransactionType.None type) {
      System.out.println("Case None received");
    } catch(ReadUncommitted type) {
      System.out.println("Case Read Uncommitted");
    } catch(ReadCommitted type) {
      System.out.println("Case Read Committed");
    } catch(RepeatableRead type) {
      System.out.println("Case Repeatable Read");
    } catch(TransactionType type) {
  public static void main(String[] args) {

Try it out, the exception handling mechanism works quite well for this. There are a few pointers you have to follow if you want to use this:

  1. Don't ever catch "Throwable" as the default case. You should rather catch the type base class, such as TransactionType. Otherwise you run the risk of catching RuntimeException and Error classes, such as OutOfMemoryError.
  2. Make sure that ALL the types are public inner classes of the type base class.
  3. Make sure that all the constructors are private.
  4. Lastly, rather use polymorphism to achieve this effect. Switch/Case code is really messy to maintain and very error- prone.

I've already donned my asbethos suit for the criticisms from hard-nosed C/C++ programmers who think switch/case is great and from weeny Java purists who think that switch/case is completely unacceptable. Flame away...

Until next week, and please remember to forward this newsletter in its entirety to as many Java users as you know.



Related Articles

Browse the Newsletter Archive

About the Author


Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

Nobody ever wants to call a Java performance consultant, but with first-hand experience repairing and improving commercial Java applications - JavaSpecialists are a good place to start...

Threading Emergency?

If your system is down, we will review it for 15 minutes and give you our findings for just 1 € without any obligation.