使用Java8的更好方法

使用Java8的更好方法,java,java-8,java-stream,Java,Java 8,Java Stream,我将以下代码转换为Java8代码。我想知道我是否做得很好,还是有其他好方法 爪哇7 for (final Category category : categories) { final List<Category> subCategories = getCategories(category); if (subCategories != null) { currentLevel.addAll(subCategories); }

我将以下代码转换为Java8代码。我想知道我是否做得很好,还是有其他好方法

爪哇7

for (final Category category : categories) {
      final List<Category> subCategories = getCategories(category);
      if (subCategories != null) {
        currentLevel.addAll(subCategories);
      }
    }
任何Java8方法都可以将以下代码解析为紧凑形式

while (CollectionUtils.isNotEmpty(currentLevel)) {
  for (final Iterator<Category> iterator = currentLevel.iterator(); iterator.hasNext();) {
    final Category category = iterator.next();
    if (result == null) {
      result = new HashSet<Category>();
    }
    if (!result.add(category)) {
      // avoid cycles by removing all which are already found
      iterator.remove();
    }
  }

  if (currentLevel.isEmpty()) {
    break;
  }
  final Collection<Category> nextLevel = getAllSubcategories(currentLevel);
  currentLevel = nextLevel;
}
while(CollectionUtils.isNotEmpty(currentLevel)){
for(final Iterator Iterator=currentLevel.Iterator();Iterator.hasNext();){
final Category=iterator.next();
如果(结果==null){
结果=新的HashSet();
}
如果(!result.add(类别)){
//通过删除所有已找到的循环来避免循环
iterator.remove();
}
}
if(currentLevel.isEmpty()){
打破
}
最终收集nextLevel=getAllSubcategories(当前级别);
currentLevel=nextLevel;
}

可能是您的偏好,但您可以使用方法引用替换这些lambda:

categories.stream()
          .map(this::getCategories)
          .filter(Objects::nonNull)
          .flatMap(List::stream)
          .collect(Collectors.toList())
太糟糕了,列表可能是空的,显然(真的?)。。。否则,您可以只使用
flatMap


我不会在另一个流操作中使用
parallelStream

您的解决方案是可以的,只是到并行流的平面映射是无用的。如果您查看OpenJDK/OracleJDK中的实现,您可以看到通过lambda创建的流被传递到
flatMap
中,该流立即转变为顺序模式。因此,您将没有任何并行性,最好将
parallelStream()
替换为
stream()
,以避免混淆。如果您真的想并行化工作,通常最好只并行化最外层的流。

对于第二个问题,通常基于流的方法是将元素复制到不同的集合中,使用
distinct()
操作处理它们:

    Collection<Category> currentCopy = currentLevel.stream()
        .distinct()
        .collect(toList());
Collection currentCopy=currentLevel.stream()
.distinct()
.collect(toList());
但你似乎是在试图就地操纵收藏,而不是复制。为此,您可以执行以下操作:

    Set<Category> result = new HashSet<>();
    currentLevel.removeIf(cat -> !result.add(cat));
Set result=new HashSet();
currentLevel.removeIf(cat->!result.add(cat));

请注意,这不是streams操作,因此不能并行运行。无论如何,你不能获得太多的并行性,因为谓词有副作用。

对我来说,它看起来很好。更新…我在开始时错过了一个子句。flatMap(cat->cat.parallelStream())你只是想以唯一的类别结束吗?如果是这样,您可以只使用@stholzm的解决方案,而使用
Collectors.toSet()
。或者,如果需要列表,请在
flatMap
之后添加
.distinct()
步骤。是否确实需要第三方库来调用
currentLevel.isEmpty()
?@Holger Apache Commons
CollectionUtils.isNotEmpty
以及相关方法是“空安全的”,因为空集合被视为空。不是我喜欢的,但是很多人喜欢这种风格。看起来很优雅+1.我将尝试删除空条件。如何使用我更新的迭代器。如果您使用的是
迭代器
,它不会有多大的改进。为什么要使用迭代器来执行此操作?这就像问“我如何用这把镊子建造一座沙堡”。你可以做到,但这比使用合适的工具来完成这项工作要长得多,也要困难得多。@LouisWasserman:噢,迭代器是我提到的第二个问题。抱歉搞混了。看起来这和流不可能有关系。例如,你不能对流执行任何类似于迭代器的操作。remove()。你所说的“因为谓词有副作用”是什么意思?@Jean-FrançoisSavard纯函数只能通过从输入中读取值并对这些值执行计算来产生结果。一个不纯的函数,或者一个有副作用的函数,除了从它的输入计算结果之外,还做其他事情。在我的示例中,谓词
cat->!结果。添加(cat)
变异
结果
。那是副作用。如果将其转换为并行流,则多个线程将同时变异
result
,这将导致损坏,因为
HashSet
不是线程安全的。这反过来又需要同步或使用
ConcurrentHashMap
    Set<Category> result = new HashSet<>();
    currentLevel.removeIf(cat -> !result.add(cat));