Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a neat method out of three similar ones using generics

Tags:

java

generics

I've tried to do some stuff with generics already but it seems I cannot personally find any simple solution. Still I think it'd be a sin to leave these 3 similar methods alone as they are.

    public List<PassengerPlane> getPassengerPlanes() {
        List<PassengerPlane> passengerPlanes = new ArrayList<>();
        for (Plane plane : planes) {
            if (plane instanceof PassengerPlane) {
                passengerPlanes.add((PassengerPlane) plane);
            }
        }
        return passengerPlanes;
    }

    public List<MilitaryPlane> getMilitaryPlanes() {
        List<MilitaryPlane> militaryPlanes = new ArrayList<>();
        for (Plane plane : planes) {
            if (plane instanceof MilitaryPlane) {
                militaryPlanes.add((MilitaryPlane) plane);
            }
        }
        return militaryPlanes;
    }

    public List<ExperimentalPlane> getExperimentalPlanes() {
        List<ExperimentalPlane> experimentalPlanes = new ArrayList<>();
        for (Plane plane : planes) {
            if (plane instanceof ExperimentalPlane) {
                experimentalPlanes.add((ExperimentalPlane) plane);
            }
        }
        return experimentalPlanes;
    }
like image 293
in7hesky Avatar asked Jul 28 '20 19:07

in7hesky


2 Answers

What do you need is generic method, but the problem is that instanceof cannot check against type parameter (it is in fact erased during compilation), it requires actual class reference. So, you may provide this to the method explicitly:

public <T extends Plane> List<T> getPlanes(Class<T> claz) {
  List<T> result = new ArrayList<>();
  for (Plane plane : planes) {
    if (claz.isInstance(plane)) {
      result.add(claz.cast(plane));
    }
  }
  return result;
}

Note how instanceof and explicit cast changed to calls to .isInstance() and .cast()

Use it like

getPlanes(PassengerPlane.class)
like image 134
Vasily Liaskovsky Avatar answered Oct 09 '22 12:10

Vasily Liaskovsky


You can make things a bit shorter with Streams, but I'm not sure there's a way to get around using instanceof here:

public List<PassengerPlane> getPassengerPlanes() {
    return planes.stream().filter(t -> t instanceof PassengerPlane)
                 .map(t -> (PassengerPlane) t).collect(Collectors.toList());
}
public List<MilitaryPlane> getMilitaryPlanes() {
    return planes.stream().filter(t -> t instanceof MilitaryPlane)
                 .map(t -> (MilitaryPlane) t).collect(Collectors.toList());
}
public List<ExperimentalPlane> getExperimentalPlanes() {
    return planes.stream().filter(t -> t instanceof ExperimentalPlane)
                 .map(t -> (ExperimentalPlane) t).collect(Collectors.toList());
}
like image 2
ajc2000 Avatar answered Oct 09 '22 14:10

ajc2000