列出<base />到List <long> ...条件转换

时间:2016-08-30 10:35:53

标签: lambda java-8 type-conversion java-stream predicate

假设我有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的实例,我想返回getPartNr

3 个答案:

答案 0 :(得分:3)

假设类的数量可能增长,您可能必须将类型的映射抽象为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));
}

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());

答案 1 :(得分:2)

首先,如果不存在所有类应该实现的公共方法,那么接口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());

答案 2 :(得分:1)

您可以尝试按照其元素类对baseList进行分组。

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; };
  }
}