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

jamis
The following is cross-posted from the original Ray Tracer Challenge forum, from a post by garfieldnate. I’m cross-posting it so that the...
New
Alexandr
Hi everyone! There is an error on the page 71 in the book “Programming machine learning from coding to depp learning” P. Perrotta. You c...
New
simonpeter
When I try the command to create a pair of migration files I get an error. user=&gt; (create-migration "guestbook") Execution error (Ill...
New
brunogirin
When trying to run tox in parallel as explained on page 151, I got the following error: tox: error: argument -p/–parallel: expected one...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
mert
AWDWR 7, page 152, page 153: Hello everyone, I’m a little bit lost on the hotwire part. I didn’t fully understand it. On page 152 @rub...
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
SlowburnAZ
Getting an error when installing the dependencies at the start of this chapter: could not compile dependency :exla, "mix compile" failed...
New
dachristenson
I just bought this book to learn about Android development, and I’m already running into a major issue in Ch. 1, p. 20: “Update activity...
New
dachristenson
I’ve got to the end of Ch. 11, and the app runs, with all tabs displaying what they should – at first. After switching around between St...
New

Other popular topics Top

AstonJ
A thread that every forum needs! Simply post a link to a track on YouTube (or SoundCloud or Vimeo amongst others!) on a separate line an...
New
DevotionGeo
I know that these benchmarks might not be the exact picture of real-world scenario, but still I expect a Rust web framework performing a ...
New
AstonJ
Or looking forward to? :nerd_face:
498 13326 269
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
There’s a whole world of custom keycaps out there that I didn’t know existed! Check out all of our Keycaps threads here: https://forum....
New
PragmaticBookshelf
Build highly interactive applications without ever leaving Elixir, the way the experts do. Let LiveView take care of performance, scalabi...
New
PragmaticBookshelf
Build efficient applications that exploit the unique benefits of a pure functional language, learning from an engineer who uses Haskell t...
New
New
AstonJ
If you’re getting errors like this: psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
New
PragmaticBookshelf
Explore the power of Ash Framework by modeling and building the domain for a real-world web application. Rebecca Le @sevenseacat and ...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: