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

iPaul
page 37 ANTLRInputStream input = new ANTLRInputStream(is); as of ANTLR 4 .8 should be: CharStream stream = CharStreams.fromStream(i...
New
telemachus
Python Testing With Pytest - Chapter 2, warnings for “unregistered custom marks” While running the smoke tests in Chapter 2, I get these...
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
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
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
curtosis
Running mix deps.get in the sensor_hub directory fails with the following error: ** (Mix) No SSH public keys found in ~/.ssh. An ssh aut...
New
EdBorn
Title: Agile Web Development with Rails 7: (page 70) I am running windows 11 pro with rails 7.0.3 and ruby 3.1.2p20 (2022-04-12 revision...
New
New
ggerico
I got this error when executing the plot files on macOS Ventura 13.0.1 with Python 3.10.8 and matplotlib 3.6.1: programming_ML/code/03_...
New
New

Other popular topics Top

Exadra37
I am thinking in building or buy a desktop computer for programing, both professionally and on my free time, and my choice of OS is Linux...
New
AstonJ
I ended up cancelling my Moonlander order as I think it’s just going to be a bit too bulky for me. I think the Planck and the Preonic (o...
New
PragmaticBookshelf
Use WebRTC to build web applications that stream media and data in real time directly from one user to another, all in the browser. ...
New
Maartz
Hi folks, I don’t know if I saw this here but, here’s a new programming language, called Roc Reminds me a bit of Elm and thus Haskell. ...
New
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New
PragmaticBookshelf
Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic. Sam Ruby @rubys ...
New
PragmaticBookshelf
Overarching tutorial for Python beginner and intermediate developers that teaches web development with the Flask framework. Miguel Gr...
New
RobertRichards
Hair Salon Games for Girls Fun Girls Hair Saloon game is mainly developed for kids. This game allows users to select virtual avatars to ...
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: