Stream filter and slice

In this example we will use a base object Post that could represent a trim down version of a blog post. We will show ways to filter with a predicate, filter unique elements, filter and truncate or limit and skip the first and ignore the first few elements of a stream.

Setup

class Post {

    String description;
    String tags;
    int wordlength;

    public Post(String description, String tags, int wordlength) {
        super();
        this.description = description;
        this.tags = tags;
        this.wordlength = wordlength;
    }

    @Override
    public String toString() {

        return com.google.common.base.Objects.toStringHelper(this)
                .add("description", description).add("tags", tags)
                .add("tags", wordlength).toString();
    }

    public String getDescription() {
        return description;
    }

    public String getTags() {
        return tags;
    }

    public int getWordlength() {
        return wordlength;
    }
}

List<Post> posts;

@Before
public void setUp() {

    posts = new ArrayList<>();

    posts.add(new Post("Java 8 is jammed packed with some cool",
            "java 8, eclipse", 459));
    posts.add(new Post("The Date-Time package introduced in the Java SE 8",
            "java 8, date time api", 750));
    posts.add(new Post("Prefer empty collection to null is a basic",
            "clean code, java", 245));
    posts.add(new Post("Screencast #1: Intro to filtering collections",
            "java, java tutorial, guava", 1234));
    posts.add(new Post("Screencast #2: Intro to transforming objects",
            "java, java tutorial", 9483));
}

Filter with predicate

The Stream interface supports a filter method that takes a predicate as an argument. Below we will filter any Post that has a word length of less than 500 then converting the stream to a list.

@Test
public void filter_with_predicate() {

    List<Post> postWithLessThan500 = posts.stream()
            .filter(p -> p.wordlength < 500).collect(Collectors.toList());

    assertEquals(2, postWithLessThan500.size());
}

Filter unique elements

Streams interface also supports a distinct method. Similar to a select distinct column from table it returns a stream with unique elements according to the implmementation of the equals method. This example we will find unique list of tags. Since tags is a string seperated by a comma, we first need to split, trim and convert all elements to lower case. Finally we will call distinct and convert the stream to a list.

@Test
public void filter_unique_elements() {

    List<String> tags = posts
            .stream()
            .map(Post::getTags)
            .flatMap(
                    tag -> Arrays.stream(tag.split(",")).map(String::trim)
                            .map(String::toLowerCase))
            .map(Object::toString)
            .distinct()
            .collect(Collectors.toList());
            
    assertThat(
            tags,
            contains("java 8", "eclipse", "date time api", "clean code",
                    "java", "java tutorial", "guava"));

}

Filter and truncate

Another method that stream supports is limit which returns a stream consisting of the elements of this stream, truncated to be no longer than the parameter maxSize in length. In our example we may only want to display the first two posts to a user possibly on a main landing page or as a side nav element.

@Test
public void filter_and_truncate() {

    List<Post> firstTwoPosts = posts.stream().limit(2)
            .collect(Collectors.toList());

    logger.info(firstTwoPosts);

    assertEquals(2, firstTwoPosts.size());
}

Output

[
Post{description=Java 8 is jammed packed with some cool, tags=java
8, eclipse, tags=459}, 
Post{description=The Date-Time package
introduced in the Java SE 8, tags=java 8, date time api, tags=750}
]

Skip elements

Limit and skip complement each other. Limit truncates a stream, skip will return a stream consisting of the remaining elements after the first n elements provided as a parameter. In the instance where the stream has fewer elements than provide n, an empty stream will be returned. Using posts we will skip the first 4 elements and return the 5th element in the stream.

@Test
public void skipping_elements() {

    List<Post> firstTwoPosts = posts.stream().skip(4)
            .collect(Collectors.toList());

    logger.info(firstTwoPosts);

    assertEquals(1, firstTwoPosts.size());
}

Output

[Post{description=Screencast #2: Intro to transforming objects, tags=java, java tutorial, tags=9483}]