dtonhofer

dtonhofer

Functional Programming in Java, Second Edition: Additional subchapter on building one's own collector?

I have been thinking about how to collect “two adjacent elements” in a stream, for example transform a stream of Long into a stream of Pair<Long,Long> (where Pair<A,B> is a little record that does just what it says). I only came up with the idea of a stateful lambda to be used inside a Stream.map() that buffers every second element and sends an Optional<Pair> rightwards that can then be filtered by its not-emptyness" (Good idea? It won’t support parallel streams for sure; this could also be used for illustration in Chapter 12 - “Avoid Side-Effects in Functional Pipelines”)

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Experimental {

    record PairOfInt(Integer a, Integer b) {

        @Override
        public String toString() {
            return "(" + a + ", " + b + ")";
        }

    }

    // Problems:
    // 1) We lost the last element in a stream with an odd number of elements
    // 1) If the stream is run "in parallel" anything can happen here.
    //    It would definitely be necessary to synchronize the "stash"
    // 2) Is there a way to make sure and make evident in code that
    //    a stream cannot be run in parallel so that the next developer
    //    doesn't try something stupid?

    public Function<Integer, Optional<PairOfInt>> buildPairBuilder() {
        List<Integer> stash = new ArrayList<>(1);
        return (x) -> {
            synchronized (stash) {
                if (stash.isEmpty()) {
                    stash.add(x);
                    return Optional.empty();
                } else {
                    return Optional.of(new PairOfInt(stash.remove(0), x));
                }
            }
        };
    }

    private static String stringify(List<PairOfInt> pairs) {
        return pairs.stream()
                .map(PairOfInt::toString)
                .collect(Collectors.joining(", "));
    }

    // Behaves well, prints out
    // (0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19) ...

    @Test
    public void runStreamSequentially() {
        var pairBuilder = buildPairBuilder();
        List<PairOfInt> pairs =
                IntStream.rangeClosed(0, 33)
                        .boxed()
                        .map(pairBuilder)
                        .filter(Optional::isPresent)
                        .map(Optional::orElseThrow)
                        .toList();
        System.out.println(stringify(pairs));
    }

    // Behaves badly, prints out for example
    // (0, 1), (2, 3), (25, 4), (31, 5), (7, 6), (10, 11), (26, 13), (12, 14), ...

    @Test
    public void runStreamParallel() {
        var pairBuilder = buildPairBuilder();
        List<PairOfInt> pairs =
                IntStream.rangeClosed(0, 33)
                        .parallel() // **** DANGER, WILL ROBINSON! ****
                        .boxed()
                        .map(pairBuilder)
                        .filter(Optional::isPresent)
                        .map(Optional::orElseThrow)
                        .toList();
        System.out.println(stringify(pairs));
    }

}

As StackOverflow exists, one can get pointers on how to (nearly) do that:

The proposed solution is to write one’s own collector, which works at the “business tail” of the stream only of course.

I haven’t tried this yet but one the idea arises that one might want to add a write your own collector subchapter to the book.

The problem of elegantly generating pair in the middle of the stream is still open :thinking: but a reader points to a 3rd-party library called StreamEx:

where you can do things like

DoubleStreamEx.of(input).pairMap((a, b) -> b-a).toArray();

But I haven’t looked at that at all.

Where Next?

Popular Pragmatic Bookshelf topics Top

jimschubert
In Chapter 3, the source for index introduces Config on page 31, followed by more code including tests; Config isn’t introduced until pag...
New
jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
mikecargal
Title: Hands-On Rust (Chapter 11: prefab) Just played a couple of amulet-less games. With a bit of debugging, I believe that your can_p...
New
leonW
I ran this command after installing the sample application: $ cards add do something --owner Brian And got a file not found error: Fil...
New
jskubick
I’m running Android Studio “Arctic Fox” 2020.3.1 Patch 2, and I’m embarrassed to admit that I only made it to page 8 before running into ...
New
jskubick
I’m under the impression that when the reader gets to page 136 (“View Data with the Database Inspector”), the code SHOULD be able to buil...
New
AufHe
I’m a newbie to Rails 7 and have hit an issue with the bin/Dev script mentioned on pages 112-113. Iteration A1 - Seeing the list of prod...
New
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
gorkaio
root_layout: {PentoWeb.LayoutView, :root}, This results in the following following error: no “root” html template defined for PentoWeb...
New

Other popular topics Top

New
PragmaticBookshelf
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
New
PragmaticBookshelf
Free and open source software is the default choice for the technologies that run our world, and it’s built and maintained by people like...
New
AstonJ
We have a thread about the keyboards we have, but what about nice keyboards we come across that we want? If you have seen any that look n...
New
AstonJ
Thanks to @foxtrottwist’s and @Tomas’s posts in this thread: Poll: Which code editor do you use? I bought Onivim! :nerd_face: https://on...
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
Margaret
Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
1147 29994 760
New
PragmaticBookshelf
Build efficient applications that exploit the unique benefits of a pure functional language, learning from an engineer who uses Haskell t...
New
PragmaticBookshelf
Programming Ruby is the most complete book on Ruby, covering both the language itself and the standard library as well as commonly used t...
New
PragmaticBookshelf
Build modern server-driven web applications using htmx. Whatever programming language you use, you’ll write less (and cleaner) code. ...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: