Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How I can rewrite this classic Java-code to Java Stream API code?

There is a old Java code (without lambda expressions):

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

I'm trying to rewrite this code to Java 8 Stream API style:

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...

PROBLEM: The function isCheckerBlocked() (which uses in last filter() operation) takes variable of VectorDirection type (variable d). But after calling map() function I lose access to this variable. How I can save access to d variable after calling map() function?

Thank you for attention.

like image 688
V. Moroz Avatar asked Feb 17 '17 16:02

V. Moroz


1 Answers

You cannot share scopes of lambdas like that. In other languages you can use tuples, so instead of returning just the result, you return result and argument.

In java you can create a custom class to host the pair of data you need or create a Tuple to host the pair of data .

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

Importing the tuple static function like this import static so.alpha.Tuple.tuple; you can map(tuple(d,f(d)))) then your next function will be filter(t->p(t._1,t._2)) and then you will map(t->t._1) or if you add getters to the tuple you can also map(Tuple::get_1)

That way you can carry on your d to the next step.

    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
like image 110
minus Avatar answered Nov 18 '22 05:11

minus