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

jdufour
Hello! On page xix of the preface, it says there is a community forum "… for help if your’re stuck on one of the exercises in this book… ...
New
HarryDeveloper
Hi @venkats, It has been mentioned in the description of ‘Supervisory Job’ title that 2 things as mentioned below result in the same eff...
New
adamwoolhether
When trying to generate the protobuf .go file, I receive this error: Unknown flag: --go_opt libprotoc 3.12.3 MacOS 11.3.1 Googling ...
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
fynn
This is as much a suggestion as a question, as a note for others. Locally the SGP30 wasn’t available, so I ordered a SGP40. On page 53, ...
New
Charles
In general, the book isn’t yet updated for Phoenix version 1.6. On page 18 of the book, the authors indicate that an auto generated of ro...
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
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New
bjnord
Hello @herbert ! Trying to get the very first “Hello, Bracket Terminal!" example to run (p. 53). I develop on an Amazon EC2 instance runn...
New
dachristenson
@mfazio23 Android Studio will not accept anything I do when trying to use the Transformations class, as described on pp. 140-141. Googl...
New

Other popular topics Top

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
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
Exadra37
Please tell us what is your preferred monitor setup for programming(not gaming) and why you have chosen it. Does your monitor have eye p...
New
DevotionGeo
I know that -t flag is used along with -i flag for getting an interactive shell. But I cannot digest what the man page for docker run com...
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
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
AstonJ
Was just curious to see if any were around, found this one: I got 51/100: Not sure if it was meant to buy I am sure at times the b...
New
PragmaticBookshelf
Author Spotlight: Peter Ullrich @PJUllrich Data is at the core of every business, but it is useless if nobody can access and analyze ...
New
AstonJ
Curious what kind of results others are getting, I think actually prefer the 7B model to the 32B model, not only is it faster but the qua...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: