Java multi-type method parameter?

egelev picture egelev · Dec 16, 2014 · Viewed 13.7k times · Source

I wonder if it is possible to require that a java method parameter is of any type from finite set of types. For example - I am using a library where two (or more) types have common methods, but their lowest common ancestor in the type hierarchy is Object. What I mean here:

   public interface A {
      void myMethod();
   }

   public interface B {
      void myMethod();
   }
...
   public void useMyMethod(A a) {
      // code duplication
   }

   public void useMyMethod(B b) {
      // code duplication
   }

I want to avoid the code duplication. What I think of is something like this:

   public void useMyMethod(A|B obj){
      obj.myMethod();
   }

There is similar type of syntax in java already. For example:

  try{
     //fail
  } catch (IllegalArgumentException | IllegalStateException e){
     // use e safely here
  }

Obviously this is not possible. How can I achieve well designed code using such type of uneditable type hierarchy ?

Answer

Yogster picture Yogster · Dec 16, 2014

What about passing the function as a parameter to your useMyMethod function?

If you are using Java < 8:

public interface A {
    void myMethod();
}

public interface B {
    void myMethod();
}

public void useMyMethod(Callable<Void> myMethod) {
    try {
        myMethod.call();
    } catch(Exception e) {
        // handle exception of callable interface
    }
}

//Use

public void test() {
    interfaceA a = new ClassImplementingA();
    useMyMethod(new Callable<Void>() {
        public call() {
            a.myMethod();
            return null;
        }
    });

    interfaceB b = new ClassImplementingB();
    useMyMethod(new Callable<Void>() {
        public call() {
            b.myMethod();
            return null;
        }
    });
}

For Java >= 8, you could use Lambda Expressions:

public interface IMyMethod {
    void myMethod();
}

public void useMyMethod(IMyMethod theMethod) {
    theMethod.myMethod();
}

//Use

public void test() {
    interfaceA a = new ClassImplementingA();
    useMyMethod(() -> a.myMethod());

    interfaceB b = new ClassImplementingB();
    useMyMethod(() -> b.myMethod());
}