简体   繁体   中英

How to user generic parameters in method to restrict the parameter type to some specific Class types?

I have a method named getInfo() . It have only one parameter but the parameter can have only two possible types, Exception or self-defined class CLAZZ_A . So, when I define this method getInfo() , I want to restrict its parameter types to those both. What can I do? I believe Java generic types may be useful but I don't know how to do it.

Maybe just overload:

getInfo(Exception e){}
getInfo(MyClass mc){}

This way, you'll know what your argument is at compile time and be guaranteed that it's one of the two acceptable ones. You can, through casting, call one from the other if the behaviour is similar enough.

If this is unappealing, consider making your object extend Exception (if that's relevant), that way getInfo(Exception e){} would suffice.

In generics, a type parameter can have multiple bounds in the form: <T extends B1 & B2 & B3 ... > . So if you want to restrict a method's parameter to 2 types, try something like this. (CLAZZ_A must be an interface for this to work)

class SomeClass {    
    <T extends Exception & CLAZZ_A> void doSomething(T t) {
        // ...
    }    
}

If you don't like the overload, you can create something like Try monad. Such monad normally represents either the successful result of something or the failure which is described by some exception. Probably this is close to your scenario.

// Represents either some successful result of type T or failure
public class Try<T> {
  final T value;
  final Exception ex;

  private Try(T value, Exception ex) {
    this.value = value;
    this.ex = ex;
  }

  // Construct Try with normal value
  public static <T> Try<T> of(T value) {
    return new Try<>(value, null);
  }

  // Construct an exceptional Try with given exception
  public static <T> Try<T> exceptional(Exception ex) {
    return new Try<>(null, ex);
  }

  // Run given Callable and construct either successful Try or exceptional
  // based on result
  public static <T> Try<T> run(Callable<T> c) {
    try {
      return of(c.call());
    }
    catch(Exception ex) {
      return exceptional(ex);
    }
  }

  // Return true if this Try represents successful result
  public boolean isSuccess() {
    return ex == null;
  }

  // return stored value or throw an exception if this Try is exceptional
  public T get() throws Exception {
    if(ex != null) throw ex;
    return value;
  }

  // Returns result of this Try or supplied default result if this Try
  // is exceptional
  public T getOrDefault(T defaultValue) {
    if(ex != null) return defaultValue;
    return value;
  }

  // Returns exception of exceptional Try or null for successful Try
  public Exception getException() {
    return ex;
  }
}

It's just a rough sketch. You can add other convenience methods or use some ready library which provides similar class.

Now you can declare your method like this:

void getInfo(Try<CLAZZ_A> value) { ... }

And use like this:

getInfo(Try.of(new CLAZZ_A()));

Or

getInfo(Try.exceptional(new Exception()));

Or (using Java-8 syntax)

getInfo(Try.run(() -> fetchTheCLAZZ_A()));

So now you have strict type control: you can pass only Try object which can hold either CLASS_A object or the Exception . Using Try methods you can conveniently handle both cases inside the getInfo method and you don't need any type casts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM