Reputation: 856
I am trying to use Java streams to filter out a base vehicle class that has car, motorbike, etc. sub classes. There is a parameter called vehicleType that can be CAR, MOTORBIKE, etc. I am trying to create a streaming filter in such a way that List<BaseVehicleEntity<?>> vehicleEntities contains only cars if the vehicleType is CAR, or if vehicleType is anything else, I filter out everything that ISN'T a CAR.
I have tried the following code, but it isn't working. My compiler gives a warning that the second .filter() is being ignored, so I am doing something wrong.
List<BaseVehicleEntity<?>> vehicleEntities = findTasks();
if (vehicleType.equals("CAR")) {
vehicleEntities.stream()
.filter(obj -> obj instanceof CarEntity)
.map(obj -> (CarEntity) obj)
.filter(obj -> obj.getVehicleType().equals("CAR"));
} else vehicleEntities.stream()
.filter(obj -> obj instanceof CarEntity)
.map(obj -> (CarEntity) obj)
.filter(obj -> !obj.getVehicleType().equals("CAR"));
Upvotes: 1
Views: 339
Reputation: 19565
As mentioned earlier, a terminal operation such as collect(Collectors.toList())
needs to be added to return the filtered list.
The requested functionality may be implemented using a separate Predicate
to filter the cars depending on vehicleType
as follows:
public static List<BaseVehicleEntity> filterByCar(String vehicleType, List<BaseVehicleEntity> vehicles) {
Predicate<CarEntity> condition = (car) -> "CAR".equals(car.getVehicleType());
if (!"CAR".equals(vehicleType)) {
condition = condition.negate();
}
return vehicles.stream()
.filter(v -> v instanceof CarEntity)
.map(CarEntity.class::cast)
.filter(condition)
.collect(Collectors.toList());
}
Example test (LightCar
and HeavyCar
extend CarEntity
, HeavyCar
has vehicle type = "SUV"
):
System.out.println(filterByCar("CAR", Arrays.asList(
new CarEntity(), new MotorbikeEntity(), new LightCar(), new HeavyCar())));
System.out.println(filterByCar("NOTCAR", Arrays.asList(
new CarEntity(), new MotorbikeEntity(), new LightCar(), new HeavyCar())));
Output:
[CarEntity: CAR, LightCar: CAR]
[HeavyCar: SUV]
Upvotes: 1
Reputation: 40308
First and foremost, a stream must have a terminal operator to actually do anything; terminal operators are e.g. forEach
or collect
. Notice the Javadocs, they mention that these are terminal operators explicitly. So, your code will actually do nothing until you collect it to a List
(if a List
is what you want - there are collectors for many standard collection types, e.g. toSet
):
List<CarEntity> cars = vehicleEntities.stream()
.filter(obj -> obj instanceof CarEntity)
.map(obj -> (CarEntity) obj)
.filter(obj -> obj.getVehicleType().equals("CAR"))
.collect(Collectors.toList());
Also consider the partitioningBy
collector, which will split the list according to your predicate in a single traversal.
Upvotes: 0
Reputation: 686
I think issue is that you doesn't collect your filtered collection. filter
and map
not terminal operations in stream api. So I could suggest next thing:
List<BaseVehicleEntity<?>> vehicleEntities = findTasks();
if (vehicleType.equals("CAR")) {
List<CarEntity> cars = vehicleEntities.stream()
.filter(obj -> obj instanceof CarEntity)
.map(obj -> (CarEntity) obj)
.filter(obj -> obj.getVehicleType().equals("CAR"))
.collect(Collectors.toList());
} else {
List<CarEntity> notCars = vehicleEntities.stream()
.filter(obj -> obj instanceof CarEntity)
.map(obj -> (CarEntity) obj)
.filter(obj -> !obj.getVehicleType().equals("CAR"))
.collect(Collectors.toList())
}
More information could be found here
Upvotes: 0
Reputation: 1
You need to specify a terminal operation like .collect or .reduce.
Upvotes: 0