按元素类型拆分列表
Split a list by the type of element
对于下面的代码片段:
List<ParentClass> ls = new ArrayList<ParentClass>();
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());
List<ChildClass1> sub1 = new ArrayList<ChildClass1>();
List<ChildClass2> sub2 = new ArrayList<ChildClass2>();
for (ParentClass p : ls) {
if(p instanceof ChildClass1){
sub1.add((ChildClass1)p);
} else {
sub2.add((ChildClass2)p);
}
}
System.out.println(sub1);
System.out.println(sub2);
有没有一种优雅的方法来获取sub1和sub2?我试过返回 Collection《ParentClass》的 Guava Collections2.filter(),而我需要 Collection《ChildClass1》,知道吗?
Collection<ParentClass> sub1= Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))
我认为这方面的东西应该行得通
Collection<ChildClass1> sub1 = ls.stream()
.filter (x -> x instanceof ChildClass1)
.map ( x-> (ChildClass1) x)
.collect(Collectors.asList());
Guava 假定如果您正在过滤 T
类型的元素,那么结果您仍然会得到 T
的集合(原始集合的子集合)。它不能以任何方式推断 Predicates.instanceOf(SubT.class)
过滤器导致安全类型转换,即使它确实会产生 SubT
列表。因此,您需要自己对 Collection<ChildClass1>
进行显式转换。或者,准确地说 - 首先转换为原始列表,然后转换为 Collection<ChildClass1>
以绕过编译器类型检查。
Collection<ChildClass1> sub1= (Collection<ChildClass1>) (Collection) Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))
最 "guava" 的方法如下:
List<ParentClass> ls = ... ;
FluentIterable<ParentClass> it = FluentIterable.from(ls);
List<ChildClass1> sub1 = it.filter(ChildClass1.class).toList();
List<ChildClass2> sub2 = it.filter(ChildClass2.class).toList();
请注意,它会导致两次不同的迭代(或者实际上是您调用 toList()
的次数)。
如果您只需要一次迭代,恐怕目前唯一的解决方案正是您在问题中所写的。
使用 Guava 和 single-pass 可以执行索引操作:
ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
.index(Object::getClass);
List<ChildClass1> sub1 = (List<ChildClass1>) index.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) index.get(ChildClass2.class);
在 Java-8 之前将 Object::getClass
替换为匿名 class:
ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
.index(new Function<ParentClass, Class<?>>() {
@Override
public Class<?> apply(ParentClass o) {
return o.getClass();
}
});
流 API 等效如下:
Map<?, List<ParentClass>> map = ls.stream().collect(Collectors.groupingBy(Object::getClass));
List<ChildClass1> sub1 = (List<ChildClass1>) (List<?>)map.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) (List<?>)map.get(ChildClass2.class);
不幸的是,未经检查的转换仍然是必要的。
对于下面的代码片段:
List<ParentClass> ls = new ArrayList<ParentClass>();
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());
ls.add(new ChildClass2());
ls.add(new ChildClass1());
ls.add(new ChildClass2());
List<ChildClass1> sub1 = new ArrayList<ChildClass1>();
List<ChildClass2> sub2 = new ArrayList<ChildClass2>();
for (ParentClass p : ls) {
if(p instanceof ChildClass1){
sub1.add((ChildClass1)p);
} else {
sub2.add((ChildClass2)p);
}
}
System.out.println(sub1);
System.out.println(sub2);
有没有一种优雅的方法来获取sub1和sub2?我试过返回 Collection《ParentClass》的 Guava Collections2.filter(),而我需要 Collection《ChildClass1》,知道吗?
Collection<ParentClass> sub1= Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))
我认为这方面的东西应该行得通
Collection<ChildClass1> sub1 = ls.stream()
.filter (x -> x instanceof ChildClass1)
.map ( x-> (ChildClass1) x)
.collect(Collectors.asList());
Guava 假定如果您正在过滤 T
类型的元素,那么结果您仍然会得到 T
的集合(原始集合的子集合)。它不能以任何方式推断 Predicates.instanceOf(SubT.class)
过滤器导致安全类型转换,即使它确实会产生 SubT
列表。因此,您需要自己对 Collection<ChildClass1>
进行显式转换。或者,准确地说 - 首先转换为原始列表,然后转换为 Collection<ChildClass1>
以绕过编译器类型检查。
Collection<ChildClass1> sub1= (Collection<ChildClass1>) (Collection) Collections2.filter(ls, Predicates.instanceOf(ChildClass1.class))
最 "guava" 的方法如下:
List<ParentClass> ls = ... ;
FluentIterable<ParentClass> it = FluentIterable.from(ls);
List<ChildClass1> sub1 = it.filter(ChildClass1.class).toList();
List<ChildClass2> sub2 = it.filter(ChildClass2.class).toList();
请注意,它会导致两次不同的迭代(或者实际上是您调用 toList()
的次数)。
如果您只需要一次迭代,恐怕目前唯一的解决方案正是您在问题中所写的。
使用 Guava 和 single-pass 可以执行索引操作:
ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
.index(Object::getClass);
List<ChildClass1> sub1 = (List<ChildClass1>) index.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) index.get(ChildClass2.class);
在 Java-8 之前将 Object::getClass
替换为匿名 class:
ImmutableListMultimap<Class<?>, ? extends ParentClass> index = FluentIterable.from(ls)
.index(new Function<ParentClass, Class<?>>() {
@Override
public Class<?> apply(ParentClass o) {
return o.getClass();
}
});
流 API 等效如下:
Map<?, List<ParentClass>> map = ls.stream().collect(Collectors.groupingBy(Object::getClass));
List<ChildClass1> sub1 = (List<ChildClass1>) (List<?>)map.get(ChildClass1.class);
List<ChildClass2> sub2 = (List<ChildClass2>) (List<?>)map.get(ChildClass2.class);
不幸的是,未经检查的转换仍然是必要的。