List<Base> 到 List<Long> ... 条件转换
List<Base> to List<Long> ... conditional cast
假设我有那 3 个 类(大大减少):
public interface Base
{
String getType();
}
public class Object1 implements Base
{
String getType() { ... };
long getSerialNr() { ... };
}
public class Object2 implements Base
{
String getType() { ... };
long getPartNr() { ... };
}
我如何(使用 Java 8 个流)使用条件转换将 List<Base>
转换为 List<Long>
?我从这个开始:
List<Long> result = baseList.stream().filter(Objects::nonNull)
.filter(Object1.class::isInstance)
.map(Object1.class::cast)
.map(o -> o.getSerialNr())
.collect(Collectors.toList());
...但是我如何整合第二种情况,其中元素是 Object2
的一个实例,我想 return getPartNr
?
假设类的数量可能会增长,你可能要抽象出类型映射到属性:
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));
}
get
方法假定谓词是互斥的,在测试这些非 interface
类型时就是这种情况。
然后,您可以像这样使用它:
List<Long> result = baseList.stream()
.flatMap(YourClass::get)
.collect(Collectors.toList());
您也可以内联 get
方法,但这并没有提高可读性:
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());
首先,如果没有所有 类 都应该实现的通用方法,接口 Base 就没有意义。如果你想那样做,那就不好了。您应该将代码更改为下面的代码:
List<Long> aList = baseList.stream().filter((Objects::nonNull)
.filter(obj->(obj instanceof Object1 || obj instanceof Object2))
.map(num-> (num instanceof Object1) ? ((Object1) num).getPratNr() : ((Object2) num).getPratNr())
.collect(Collectors.toList());
您可以尝试按其元素对 baseList 进行分组 class。
public class MyTest {
@Test
public void java8_listbase_to_listlong_conditional_cast() {
List<Base> baseList = new ArrayList<>();
baseList.add(new Object1());
baseList.add(new Object2());
Map<?, List<Base>> group = baseList.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key -> key.getClass()));
Stream<Long> object1stream = group.get(Object1.class)
.stream()
.map(Object1.class::cast)
.map(Object1::getSerialNr);
Stream<Long> object2stream = group.get(Object2.class)
.stream()
.map(Object2.class::cast)
.map(Object2::getPartNr);
List<Long> longList = Stream.concat(object1stream, object2stream).collect(Collectors.toList());
assertArrayEquals(new Long[] {0l, 1l}, longList.toArray());
}
public interface Base {
}
public class Object1 implements Base {
long getSerialNr() { return 0L; };
}
public class Object2 implements Base {
long getPartNr() { return 1L; };
}
}
假设我有那 3 个 类(大大减少):
public interface Base
{
String getType();
}
public class Object1 implements Base
{
String getType() { ... };
long getSerialNr() { ... };
}
public class Object2 implements Base
{
String getType() { ... };
long getPartNr() { ... };
}
我如何(使用 Java 8 个流)使用条件转换将 List<Base>
转换为 List<Long>
?我从这个开始:
List<Long> result = baseList.stream().filter(Objects::nonNull)
.filter(Object1.class::isInstance)
.map(Object1.class::cast)
.map(o -> o.getSerialNr())
.collect(Collectors.toList());
...但是我如何整合第二种情况,其中元素是 Object2
的一个实例,我想 return getPartNr
?
假设类的数量可能会增长,你可能要抽象出类型映射到属性:
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));
}
get
方法假定谓词是互斥的,在测试这些非 interface
类型时就是这种情况。
然后,您可以像这样使用它:
List<Long> result = baseList.stream()
.flatMap(YourClass::get)
.collect(Collectors.toList());
您也可以内联 get
方法,但这并没有提高可读性:
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());
首先,如果没有所有 类 都应该实现的通用方法,接口 Base 就没有意义。如果你想那样做,那就不好了。您应该将代码更改为下面的代码:
List<Long> aList = baseList.stream().filter((Objects::nonNull)
.filter(obj->(obj instanceof Object1 || obj instanceof Object2))
.map(num-> (num instanceof Object1) ? ((Object1) num).getPratNr() : ((Object2) num).getPratNr())
.collect(Collectors.toList());
您可以尝试按其元素对 baseList 进行分组 class。
public class MyTest {
@Test
public void java8_listbase_to_listlong_conditional_cast() {
List<Base> baseList = new ArrayList<>();
baseList.add(new Object1());
baseList.add(new Object2());
Map<?, List<Base>> group = baseList.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key -> key.getClass()));
Stream<Long> object1stream = group.get(Object1.class)
.stream()
.map(Object1.class::cast)
.map(Object1::getSerialNr);
Stream<Long> object2stream = group.get(Object2.class)
.stream()
.map(Object2.class::cast)
.map(Object2::getPartNr);
List<Long> longList = Stream.concat(object1stream, object2stream).collect(Collectors.toList());
assertArrayEquals(new Long[] {0l, 1l}, longList.toArray());
}
public interface Base {
}
public class Object1 implements Base {
long getSerialNr() { return 0L; };
}
public class Object2 implements Base {
long getPartNr() { return 1L; };
}
}