如何使用Java流打印嵌套列表,其中对象包含对其自身的引用列表

时间:2018-10-13 22:53:04

标签: java java-8 java-stream tostring

我有一个看起来与下面所示相似的对象:

public class Obj {
  private List<Obj> objs;
  private String objId;

  public List<Obj> getObjs() {
    return objs;
  }

  public String getobjId() {
    return objId;
  }

  @Override
  public String toString() {
    return "Obj [objs=" + objs + ", objId=" + objId + "]";
  }

}

如何使用流打印objId的列表?

编辑

Obj可以包含Obj的列表,并且其子级可以包含obj对象的列表。如果深度为5级,则可以将所有objId值从最顶部的obj打印到第5级的子级的值。我想避免嵌套的循环。

2 个答案:

答案 0 :(得分:5)

您应该使用递归。使用流执行此操作的一种可能方法如下:

private Stream<Obj> allObjs() {
    return Stream.concat(
        Stream.of(this), 
        objs == null ? Stream.empty() : objs.stream().flatMap(Obj::allObjs));
}

@Override
public String toString() {
    return allObjs()
        .map(Obj::getobjId)
        .collect(Collectors.joining(", "));
}

请注意,只要您的Obj实例以树状结构排列,此方法就可以很好地工作。如果您有一个特定的Obj实例,该实例既是某个级别的父级,又是某个较低级别的子级(例如,如果您的Obj实例形成一个图),则此解决方案将不起作用,您会会得到巨大的StackOverflowError


如果您无法修改Obj类,则可以使用接收Obj实例的辅助方法(即在ObjService类中)实现相同的目的

public static Stream<Obj> allObjs(Obj o) {
    if (o == null) return Stream.empty(); // in case the argument is null
    return Stream.concat(
            Stream.of(o), 
            o.getObjs() == null ?
                Stream.empty() :
                o.getObjs().stream().flatMap(ObjService::allObjs));
}

public static String deepToString(Obj o) {
    return ObjService.allObjs(o)
        .map(Obj::getobjId)
        .collect(Collectors.joining(", "));
}

答案 1 :(得分:1)

好吧,您可以使用Stream从这里开始:

objs.stream().
            map(Obj::getObjId).
            forEachOrdered(System.out::println);

还有一点改进:

    List<String> collect = objs.stream()
            .filter(Objects::nonNull) // Filter only nonNull objects. Avoid NullPointerException
            .map(Obj::getObjId)
            .peek(System.out::println) // Print the ObjId value from Obj
            .collect(Collectors.toList()); // Return the result to a List, if you need.

现在,您拥有从孩子那里获得价值的基本方法。了解有关Stream的知识并改进代码示例;)

一些不错的链接:

希望这会有所帮助!