Lets say I have those 3 classes (strongly reduced) :
public interface Base
{
String getType();
}
public class Object1 implements Base
{
String getType() { ... };
long getSerialNr() { ... };
}
public class Object2 implements Base
{
String getType() { ... };
long getPartNr() { ... };
}
How would I (using Java 8 streams) convert a List<Base> to a List<Long> using conditional casts? I started with this:
List<Long> result = baseList.stream().filter(Objects::nonNull)
.filter(Object1.class::isInstance)
.map(Object1.class::cast)
.map(o -> o.getSerialNr())
.collect(Collectors.toList());
...but how can I integrate the second case, where the element is an instance of Object2 and I want to return getPartNr?
Assuming that the number of classes may grow, you may have to abstract the mapping of type to property:
static Map<Predicate<Base>,Function<Base,Long>> ACCESSORS;
static {
Map<Predicate<Base>,Function<Base,Long>> m=new HashMap<>();
m.put(Object1.class::isInstance, base -> ((Object1)base).getSerialNr());
m.put(Object2.class::isInstance, base -> ((Object2)base).getPartNr());
ACCESSORS=Collections.unmodifiableMap(m);
}
static Stream<Long> get(Base b) {
return ACCESSORS.entrySet().stream()
.filter(e -> e.getKey().test(b))
.map(e -> e.getValue().apply(b));
}
The get method assumes that the predicates are mutual exclusive, which is the case when testing for these non-interface types.
Then, you can use it like:
List<Long> result = baseList.stream()
.flatMap(YourClass::get)
.collect(Collectors.toList());
You could also inline the get method, but that’s not improving the readability:
List<Long> result = baseList.stream()
.flatMap(b -> ACCESSORS.entrySet().stream()
.filter(e -> e.getKey().test(b))
.map(e -> e.getValue().apply(b)))
.collect(Collectors.toList());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With