62. Tackling type patterns for instanceof and streams
Let’s consider a List<Engine>
where Engine
is an interface implemented by several classes such as HypersonicEngine
, HighSpeedEngine
, and RegularEngine
. Our goal is to filter this List
and eliminate all RegularEngine
classes that are electric and cannot pass our autonomy test. So, we can write code as follows:
public static List<Engine> filterRegularEngines(
List<Engine> engines, int testSpeed) {
for (Iterator<Engine> i = engines.iterator(); i.hasNext();){
final Engine e = i.next();
if (e instanceof RegularEngine) {
final RegularEngine popularEngine = (RegularEngine) e;
if (popularEngine.isElectric()) {
if (!hasEnoughAutonomy(popularEngine, testSpeed)) {
i.remove();
}
}
}
}
return engines;
}
But, starting with JDK 8, we can safely remove from a List
without using an Iterator
via a default
method from java.util.Collection
named public default boolean removeIf(Predicate<? super E> filter)
. If we combine this method (and, therefore, the Stream API) with type patterns for instanceof
, then we can simplify the previous code as follows:
public static List<Engine> filterRegularEngines(
List<Engine> engines, int testSpeed) {
engines.removeIf(e -> e instanceof RegularEngine engine
&& engine.isElectric()
&& !hasEnoughAutonomy(engine, testSpeed));
return engines;
}
So, whenever you have the chance to use type patterns with the Stream API, don’t hesitate.