我如何将这个经典的Java代码重写为Java Stream API代码?

时间:2017-02-17 16:49:41

标签: java collections lambda java-8 java-stream

有一个旧的Java代码(没有lambda表达式):

public List<CheckerPosition> getAttackedCheckersForPoint(CheckerPosition from, boolean isSecondPlayerOwner, boolean isQueen, VectorDirection ignoredDirection){
    List<VectorDirection> allDirections = VectorDirection.generateAllDirections();
    List<CheckerPosition> result = new ArrayList<CheckerPosition>();

    for (VectorDirection direction : allDirections){
        if (!direction.equals(ignoredDirection)){
            Checker firstCheckerOnWay = findFirstCheckerOnWay(new CheckerBaseVector(from, direction), !isQueen);
            if ((firstCheckerOnWay != null) && (firstCheckerOnWay.isSecondPlayerOwner() != isSecondPlayerOwner) && isCheckerBlocked(firstCheckerOnWay.getPosition(), direction)){
                result.add(firstCheckerOnWay.getPosition());
            }
        }
    }
    return result;
 }

我试图将此代码重写为 Java 8 Stream API 样式:

allDirections.stream()
                .filter(d -> !d.equals(ignoredDirection))
                .map(d -> findFirstCheckerOnWay(new CheckerBaseVector(from, d), !isQueen)) // In this operation I map VectorDirection element (d) to Checker variable type.
                .filter(c -> (c != null) && (c.isSecondPlayerOwner() != isSecondPlayerOwner) && isCheckerBlocked(c.getPosition(), d)); // But in this operation I need to access d variable...

问题:函数isCheckerBlocked()(在最后filter()次操作中使用)采用VectorDirection类型的变量(变量d)。但在调用map()函数后,我无法访问此变量。如何在调用d函数后保存对map()变量的访问权限?

感谢您的关注。

1 个答案:

答案 0 :(得分:5)

你不能像那样分享lambda的范围。在其他语言中,您可以使用元组,因此不返回结果,而是返回结果参数。

在java中,您可以创建一个自定义类来托管您需要的数据对,或者创建一个Tuple来托管这对数据。

public class Tuple<A,B> {
    public final A _1;
    public final B _2;
    public Tuple(A a, B b){
        _1 = a;
        _2 = b;
    }
    public static <A,B> Tuple<A,B> tuple(A a, B b){
        return new Tuple<>(a, b);
    }
}

导入像import static so.alpha.Tuple.tuple;这样的元组静态函数,你可以map(tuple(d,f(d)))),然后你的下一个函数将是filter(t->p(t._1,t._2))然后你将map(t->t._1)或者你将getter添加到元组中你也可以map(Tuple::get_1)

这样你就可以将 d 继续下一步了。

    Stream<String> s = Arrays.asList("sa","a","bab","vfdf").stream();

    Stream<Integer> result = s.map(d -> tuple(d.length(),d)) //String to Tuple<Integer,String>
        .filter(t->t._1 >= 2 && t._2.contains("a")) // Filter using both
        .map(Tuple::get_1); // Return just Integers