Java Stream#filter fails on two sequential filters

Viewed 50

I have a set of points with different possibilities. For that I created a class Point. It's importan to say that a point MUST ALWAYS HAVE AT LEAST ONE POSSIBILITY (For this example we assume this statement is true).

import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Point {

    private final HashSet<Integer> possibilities;

    public Point(int n) {
        this.possibilities = (HashSet<Integer>) IntStream.rangeClosed(1, n)
                .boxed()
                .collect(Collectors.toSet());
    }

    /**
     * Serves to verify if this point has only one
     * possibility
     * @return true if there's only one element in the
     * hashset possibilities, false otherwise
     */
    public boolean uniquePossibility() {
        return this.possibilities.size() == 1;
    }

    /**
     * @return the number of possibilities for this point
     */
    public int getCurrentPossibilities() {
        return this.possibilities.size();
    }

    /**
     * @return possibilities
     */
    public HashSet<Integer> getPossibilities() {
        return possibilities;
    }
    
    /* Lots of methods here */
}

And then I want to create a method that works with the points with 2 or 3 possibilities.

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class AwesomeClass {

    private final List<Point> points;

    public AwesomeClass() {
        points = new ArrayList(10_00_000);
        for (int i = 0; i < 10_00_000; i++) {
            Random random = new Random();
            points.add(new Point(random.nextInt(9) + 1));
        }
        spotTriplets();
    }

    private boolean spotTriplets() {
        AtomicBoolean changes = new AtomicBoolean(false);

        List<Point> triplets = points.stream()
                .filter(point -> point.getCurrentPossibilities() <= 3)
                .filter(point -> !point.uniquePossibility())
                .collect(Collectors.toList());

        triplets.forEach(point -> {
            System.out.println(point.uniquePossibility());
            List<Integer> number = new ArrayList<>(point.getPossibilities());
            int x = number.get(0);
            int y = number.get(1);
            AtomicInteger z = new AtomicInteger(0);
            
            /* Lots of beautiful code*/
            
        });

        return changes.get();
    }
}

When I run my code, this error happens

false
false
...
false
false
true
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
    at java.base/java.util.Objects.checkIndex(Objects.java:359)
    at java.base/java.util.ArrayList.get(ArrayList.java:427)
    at AwesomeClass.lambda$spotTriplets$69(AwesomeClass.java:400)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at AwesomeClass.spotTriplets(AwesomeClass.java:396)
    at AwesomeClass.solveProblem(AwesomeClass.java:71)
    at Main.main(Main.java:59)

Process finished with exit code 1

This error is on the line int y = number.get(1);. But the error actually is from the filter, please notice the filter .filter(point -> !point.uniquePossibility()) and the STDOUT: System.out.println(point.uniquePossibility());.

Is contradictory that if I have a filter dropping point.uniquePossibility(), I got a point with point.uniquePossibility() -> true.

What can I do?

Using the filter before the foreach solves the problem, but I would like to fix this on the List

triplets.stream()
        .filter(point -> !point.uniquePossibility())
        .forEach(point -> {/*code here*/});

Thanks in advance

0 Answers
Related