if-elseif-else类似的Java 8流功能

Riv*_*Riv 2 java java-8 java-stream

我有一个对象列表,可以说形状。我想使用流来处理它们,并根据列表中的内容返回另一个对象-ShapeType。

通常,我只返回ShapeType.GENERIC,但是如果其中存在Rectangle,我想返回ShapeType.RECT。如果列表中有一个六角形,我想返回ShapeType.HEXA。当同时存在矩形和正方形时,我想返回ShapeType.HEXA。

现在,当涉及到代码时,我想要这样的东西:

  public ShapeType resolveShapeType(final List<Shape> shapes) {
    shapes.stream()
    .filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
    // I should have a stream with just rectangles and hexagons if present.
    // what now?
  }
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 5

您可以使用

public ShapeType resolveShapeType(final List<Shape> shapes) {
    int sides = shapes.stream()
        .mapToInt(Shape::getSideCount)
        .filter(count -> count==4 || count==6)
        .max().orElse(0);
    return sides==6? ShapeType.HEXA: sides==4? ShapeType.RECT: ShapeType.GENERIC;
}
Run Code Online (Sandbox Code Playgroud)

这会将每个元素映射到其边数,然后将其减少为首选类型,这恰好是此处的最大数量,因此不需要自定义归约功能。

这不是短路,但是对于大多数用例而言,这已经足够了。如果要将操作数减少到必要的最低限度,事情将会变得更加复杂。

public ShapeType resolveShapeType(final List<Shape> shapes) {
    OptionalInt first = IntStream.range(0, shapes.size())
        .filter(index -> {
            int count = shapes.get(index).getSideCount();
            return count == 6 || count == 4;
        })
        .findFirst();
    if(!first.isPresent()) return ShapeType.GENERIC;
    int ix = first.getAsInt(), count = shapes.get(ix).getSideCount();
    return count==6? ShapeType.HEXA: shapes.subList(ix+1, shapes.size()).stream()
        .anyMatch(shape -> shape.getSideCount()==6)? ShapeType.HEXA: ShapeType.RECT;
}
Run Code Online (Sandbox Code Playgroud)

我们知道我们可以在第一处停下来HEXA,但是要避免第二遍,有必要记住是否存在RECT的情况HEXA。因此,它将搜索第一个元素a RECTHEXA。如果不存在,GENERIC则返回,否则,如果第一个不是a HEXA,则检查其余元素中是否存在该HEXA类型的元素。请注意,第一个后处理剩余的RECT,没有filter因为它暗示形状既不是,需要RECT也没有HEXA,不能满足条件。

但是也应该很明显的是,这种试图最小化检查次数的代码比等效的for循环更难读。