我有一个Car
列表,其中每辆车都有一个通过Engine
界面定义的引擎。在此示例中,具体类型为CombustionEngine
,具有可变数量的柱面,并且ElectricMotor
。
我想找到所有(燃烧)发动机有四个气缸。使用Java流我想出了这个管道:
Car[] carsWithFourCylinders
= cars.stream()
.filter( car -> car.engine instanceof CombustionEngine )
.filter( car -> ( ( CombustionEngine )car.engine ).cylinderCount == 4 )
.toArray( Car[]::new );
虽然这有效,我想知道是否可以避免第二个filter
谓词中的强制转换或者完全重写管道以便更具可读性?
供参考,为了体验我已附上该示例的完整来源:
public class CarTest {
interface Engine { }
class CombustionEngine implements Engine {
final int cylinderCount;
CombustionEngine( int cylinderCount ) {
this.cylinderCount = cylinderCount;
}
}
class ElectricMotor implements Engine { }
class Car {
final Engine engine;
Car( Engine engine ) {
this.engine = engine;
}
}
@Test
public void filterCarsWithFourCylinders() {
List<Car> cars = Arrays.asList( new Car( new CombustionEngine( 4 ) ),
new Car( new ElectricMotor() ),
new Car( new CombustionEngine( 6 ) ) );
Car[] carsWithFourCylinders
= cars.stream()
.filter( car -> car.engine instanceof CombustionEngine )
.filter( car -> ( ( CombustionEngine )car.engine ).cylinderCount == 4 )
.toArray( Car[]::new );
assertEquals( 1, carsWithFourCylinders.length );
}
}
答案 0 :(得分:1)
我认为没有可能避免演员表演。毕竟,Car
和Engine
都没有提供任何可以区分电动汽车和带有ICE的方法。
但如果你的Engine
没有方法,我认为这意味着Car
它的引擎类型无关紧要。
我能想到的最好的是
final List<Car> combustionCars = cars.stream()
.collect(groupingBy(c -> c.engine.getClass()))
.get(CombustionEngine.class);
long count = combustionCars
.stream()
.map(Car::getEngine)
.map(CombustionEngine.class::cast)
.filter(c -> c.cylinderCount == 4).collect(Collectors.counting());
但我不确定这是否更具可读性。