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

时间:2017-01-03 17:13:20

标签: java java-8 java-stream

我有一个对象列表,让我们说Shapes。 我想使用流处理它们并返回另一个对象 - 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?
  }

5 个答案:

答案 0 :(得分: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;
}

这会将每个元素映射到其边数并将它们缩减为首选类型,这恰好是此处的最大计数,因此不需要自定义缩减功能。

这不是短路,但对于大多数用例来说,这就足够了。如果你想将操作次数减少到必要的最小值,事情会更复杂。

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

我们知道我们可以在第一个HEXA停止,但为了避免第二次通过,有必要记住RECT是否出现HEXA的情况没有RECT }。因此,这会搜索第一个元素,即HEXAGENERIC。如果没有,则返回HEXA,否则,如果第一个不是HEXA,则检查其余元素是否为RECT类的元素。请注意,为了处理第一个filter之后的余数,不需要RECT,因为暗示既不是HEXA也不是for的形状都无法满足条件。

但同样显而易见的是,这个代码试图最小化检查数量,比同等的<span class=“standout”> <span class="standout"> 循环更难阅读。

答案 1 :(得分:4)

假设列表中只能存在三种形状,则可以选择:

Set<Integer> sides = shapes.stream()
      .map(Shape::getSideCount)
      .collect(toSet());

if (sides.contains(6)) return HEXA;
else if (sides.contains(4)) return RECTANGLE;
else return GENERIC;

但我认为最简单(也是最有效)的方式对于循环来说是一个很好的旧方法:

ShapeType st = GENERIC;
for (Shape s : shapes) {
  if (s.getSideCount() == 6) return HEXA;
  if (s.getSideCount() == 4) st = RECTANGLE;
}
return st;

答案 2 :(得分:2)

如果我了解您要执行的操作,则可以使用anyMatch。像,

public ShapeType resolveShapeType(final List<Shape> shapes) {
    if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 6)) {
        return ShapeType.HEXA;
    } else if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 4)) {
        return ShapeType.RECT;
    } else {
        return ShapeType.GENERIC;
    }
}

执行此操作的一种方法(流shapes一次)将使用数组保留形状存在。像,

public ShapeType resolveShapeType(final List<Shape> shapes) {
    boolean[] bits = new boolean[2];
    shapes.stream().forEach(shape -> {
        int sides = shape.getSideCount();
        if (sides == 4) {
            bits[0] = true;
        } else if (sides == 6) {
            bits[1] = true;
        }
    });
    if (bits[1]) {
        return ShapeType.HEXA;
    } else if (bits[0]) {
        return ShapeType.RECT;
    } else {
        return ShapeType.GENERIC;
    }
}

答案 3 :(得分:1)

也可以这样做:

ShapeType

在这里,我对你的enum ShapeType { Square(4), Hexagon(6), Generic(Integer.MAX_VALUE); int v; ShapeType(int v) { this.v = v; } static ShapeType parse(int v) { switch (v) { case 4: return Square; case 6: return Hexagon; default: break; } return Generic; } public String toString(){ return Integer.toString(v); } }

采取了一点自由
getShapeType()

如果添加map()方法,则可以避免解析操作,该方法为每个派生类型返回正确的类型。然后,.map(Shape::getShapeType)操作将仅提取类型,例如.filter()

'/users/'会找到您感兴趣的群组,最大的形状被视为该系列的标签......

答案 4 :(得分:1)

听起来像'reduce'或'collect / max'。

假设你有一个选择'显性'类型的方法(你可以将它放在一个lambda中,但恕我直言,它作为一种方法更具可读性):

public class Util{
    public static ShapeType dominantType(ShapeType t1, ShapeType t2){
        if(t1==HEXA || t2==HEXA) return HEXA;
        else if (t1==RECTANGLE || t2==RECTANGLE) return RECTANGLE;
        else return GENERIC;
    }
}

有几种方法可以使用它,一个简化示例是:

shapes.stream()
.filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
.map(shape -> shape.getSideCount()==6? HEXA:RECTANGLE)
.reduce( GENERIC,  Util::dominantType); 
 //   using GENERIC in case of empty list

您可能还想查看collectors.maxBy。 顺便说一句,无论你采取什么方法,请在空列表的情况下考虑一下行为......