{"id":23902795,"url":"https://github.com/mtumilowicz/java12-introduction-to-reactive-programming-workshop","last_synced_at":"2025-10-24T18:15:26.251Z","repository":{"id":54500042,"uuid":"216546951","full_name":"mtumilowicz/java12-introduction-to-reactive-programming-workshop","owner":"mtumilowicz","description":"Java reactive streams workshop: basic implementations of Publisher, Subscriber, Subscription and Processor.","archived":false,"fork":false,"pushed_at":"2024-05-27T07:38:13.000Z","size":167,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-15T14:14:03.192Z","etag":null,"topics":["java9-stream","processor","publisher","publisher-subscriber","reactive-streams","stream","subscription"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-21T11:04:13.000Z","updated_at":"2024-05-27T07:38:16.000Z","dependencies_parsed_at":"2022-08-13T17:50:52.860Z","dependency_job_id":null,"html_url":"https://github.com/mtumilowicz/java12-introduction-to-reactive-programming-workshop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/java12-introduction-to-reactive-programming-workshop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249085429,"owners_count":21210267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java9-stream","processor","publisher","publisher-subscriber","reactive-streams","stream","subscription"],"created_at":"2025-01-04T22:50:35.606Z","updated_at":"2025-10-24T18:15:26.170Z","avatar_url":"https://github.com/mtumilowicz.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://app.travis-ci.com/mtumilowicz/java12-introduction-to-functional-programming-workshop.svg?branch=master)](https://travis-ci.com/mtumilowicz/java12-introduction-to-functional-programming-workshop)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n# java12-introduction-to-reactive-programming-workshop\n* References\n    * [Out-of-the-box Reactive Streams with Java 9](https://www.youtube.com/watch?v=COgktgJmP_k)\n    * [Java Streams vs Reactive Streams: Which, When, How, and Why? by Venkat Subramaniam](https://www.youtube.com/watch?v=kG2SEcl1aMM)\n    * [Reactive Programming by Venkat Subramaniam](https://www.youtube.com/watch?v=weWSYIUdX6chttps://www.youtube.com/watch?v=weWSYIUdX6c)\n    * [From Functional to Reactive Programming, Venkat Subramaniam](https://www.youtube.com/watch?v=U_NgcAg7jyY)\n    * [WJUG #239 - Jacek Kunicki: Jak (nie) używać Reactive Streams w Javie 9+](https://www.youtube.com/watch?v=8zVcpjSxT1o)\n    * [GOTO 2018 • Real-world Reactive Programming in Java: The Definitive Guide • Erwin de Gier](https://www.youtube.com/watch?v=fXWywFRwHOk)\n    * https://www.manning.com/books/akka-in-action\n    * https://github.com/rucek/reactive-streams-java9\n    * https://github.com/reactive-streams/reactive-streams-jvm\n    * https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.html  \n    * https://blog.softwaremill.com/how-not-to-use-reactive-streams-in-java-9-7a39ea9c2cb3\n    * https://thepracticaldeveloper.com/2018/01/31/reactive-programming-java-9-flow/\n    * https://www.quora.com/Whats-the-difference-between-push-and-pull-protocols\n    * http://blog.amitinside.com/Java-Iterator-Pattern-vs-Stream-vs-RxObservable/\n    * http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/BackpressureStrategy.html\n    * http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/schedulers/Schedulers.html\n\n## preface\n\nThe main goal of this project is to explore basic features of \n`reactive streams` introduced in `Java 9`:\n\n* **Publisher**\n* **Subscriber**\n* **Subscription** (**Backpressure**)\n* **Processor** (**SubmissionPublisher**)\n\n## introduction\n### general overview\n* reactive programming (idea formulated by Eric Meijer)\n    * the applications we developer, the programs we create must\n    be really responsive and be able to react to stimuli in a \n    system\n* the main objective of the reactive programming is NOT to be as fast as possible \nbut to use resources (CPU, memory, ...) in the most efficient manner\n    * core idea behind reactive is to release resource whenever possible\n* reactive programming is functional programming+\n* before java 8: completely imperative + object oriented\n    * please refer: https://github.com/mtumilowicz/java12-introduction-to-functional-programming-workshop\n    * imperative: tell me what tell me how\n    * declarative: tell me what and NOT how\n* functional (style): declarative + higher-order function\n    * functional programming: function composition + lazy evaluation\n* functional programming and exceptions are mutually exclusive\n* exceptions + java 8 streams: if you are driving a car and\nhave a problem with a radio - the most illogical thing to do is to reverse back\n    * you should turn off the radio and continue journey\n* Michael Feather: OO makes code understandable by encapsulating moving parts. FP makes code understandable by \nminimizing moving parts.\n    * I moving part: immutability\n    * II moving part: control flow (in imperative - we are going up and down to follow the flow)\n### manifesto\n* https://www.reactivemanifesto.org/\n    * OOP four pillars: \n        * abstraction (programming is based on making abstractions), \n        * encapsulation (best practice for every programming style), \n        * inheritance (golang has no inheritance), \n        * polymorphism (makes actually OOP)\n    * reactive four pillars \n        * responsive\n            * infinite-scrolling\n            * providing responsiveness\n                * efficiency is attained not by doing tasks faster, but\n                by avoiding those that shouldn't be done in the first place\n        * resilient - make failure first-class citizen (it is okay\n        to fail)\n        * elastic - the only reasonable direction to scale is horizontally\n        * message driven - do not expose your database instead\n        export your data\n    * reactive manifesto conclusions\n        * blocking I/O limits opportunities for parallelism, so nonblocking I/O is preferred\n        * synchronous interaction limits opportunities for parallelism - asynchronous \n        interaction is preferred\n        * polling reduces opportunity to use fewer resources, so an event-driven style is preferred\n        * if one node can bring down all other nodes, that’s a waste of resources\n            * you need isolation of errors (resilience) to avoid losing all your work\n        * systems need to be elastic: if there’s less demand - use fewer resources\n            * if there’s more demand - use more resources, but never more than required\n            \n### concurrency context\n* shared mutability\n    ```\n    Thread th = new Thread(new Runnable() {\n        public void run() { // we don't produce anything and don't consume anything \n            // it could be useful only by shared mutability\n            // how to work with threads if shared mutability is dangerous \n            // and thread API forces us to use it\n        }\n    })\n    ```\n* in the past the structure of sequential code was very different from the structure \nof concurrent code\n    * with stream: the structure of sequential code is the same as the structure of \n    concurrent code\n* how many threads should you create?\n    * computation intensive \u003c= # of cores\n        * `Schedulers.computation()`\n    * IO intensive = `NCPU * UCPU * (1 + W/C)`\n        * NCPU is the number of cores, available through `Runtime.getRuntime().availableProcessors()`\n        * UCPU is the target CPU utilization (between 0 and 1)\n        * W/C is the ratio of wait time to compute time\n        * `Schedulers.io()`\n    * number of threads is therefore strictly limited\n        * by memory also\n* example of reactive application\n    * excel: if you modify one cell, it propagates to other cells\n    * google docs - hundreds of people use it simultaneously\n### java 8 streams\n* stream is not a data structure it is is actually a collection of functions (with a data source: network, file, etc.)\n    * Martin Fowler: [Collection Pipeline Pattern](https://martinfowler.com/articles/collection-pipeline/)\n* limitations\n    * stream cannot be reused\n    * single pipeline (a single terminal operation)\n        * cannot split into two\n    * no exceptions handling\n### reactive streams\n* vs java 8 streams\n\n    |java streams   |reactive streams   |\n    |---|---|\n    |pipeline   |pipeline   |\n    |push data   |push/pull data   |\n    |lazy   |lazy   |\n    |0, 1, oo   |0, 1, oo   |\n    |data only   |3 channels: data, error, complete   |\n    |exceptions: good luck   |deal with it downstream (error is just another form of data)  |\n    |sequential vs parallel   |synch vs async   |\n    |single pipeline (one terminal operation)   |multiple subscribers   |\n* vs CompletableFuture\n\n    |reactive streams   |CompletableFuture/Promises   |\n    |---|---|\n    |0, 1, oo   |0, 1   |\n    |3 channels |2 channels (data, error) |\n* there are three key factors that make a stream reactive:\n    * the data is processed asynchronously\n    * the backpressure (strategy of co-op with very fast producer) mechanism is non-blocking\n    * the fact that the downstream can be slower than the upstream is somehow represented in the domain model\n        * the Twitter streaming API, where you can be disconnected if consuming too slow\n* Observable (producer) vs Observer pattern\n    * it's that, plus\n        * signal end of data stream\n        * propagate error\n        * evaluation may be synchronous, asynchronous or lazy\n* nonblocking backpressure\n    * BUFFER - buffers all onNext values until the downstream consumes it\n    * DROP - drops the most recent onNext value if the downstream can't keep up\n    * ERROR - signals a MissingBackpressureException in case the downstream can't keep up\n    * LATEST - keeps only the latest onNext value, overwriting any previous value if the downstream can't keep up\n    * MISSING - OnNext events are written without any buffering or dropping\n* hot vs cold\n    * cold = every subscriber starts fresh subscription\n        * like iterator, if you start again you start from the\n        beginning\n    * hot = start from a point in time, like football online transmission\n* visualizations: https://rxmarbles.com/\n### past and future\n* times when you have to go to bank and talk with a person\n* times when you have to go to travel agency to buy tickets\n* in the past companies made products for their employees to use\nand make those employees (nobody cares what they think) available to us the customers\n* now companies build product for real-users, IOT\n### push vs pull protocols\n* summary\n\n    ![alt text](img/pull_vs_push.png)\n* push protocols: \n    * the client opens a connection to the server and keeps it constantly active\n    * the server will send (push) all new events to the client using that single always-on connection \n    * in other words, the server PUSHes the new events to the client\n* pull protocols: \n    * the client periodically connects to the server, checks for and gets (pulls) recent events and \nthen closes the connection and disconnects from the server\n    * the client repeats this whole procedure to get updated about new events\n    * in this mode, the clients periodically PULLs the new events from the server\n* code example\n    ```\n    private static void pullExample() {\n        final List\u003cString\u003e list = Lists.newArrayList(\"Java\", \"C\", \"C++\", \"PHP\", \"Go\");\n    \n        final Iterator\u003cString\u003e iterator = list.iterator();\n    \n        while (iterator.hasNext()) {\n            System.out.println(iterator.next());\n        }\n    }\n    \n    private static void pushExample() {\n        final List\u003cString\u003e list = Lists.newArrayList(\"Java\", \"C\", \"C++\", \"PHP\", \"Go\");\n    \n        final Observable\u003cString\u003e observable = Observable.from(list);\n    \n        observable.subscribe(System.out::println, System.out::println, () -\u003e System.out.println(\"We are done!\"));\n    }\n    ```\n\n## definitions\n\n* **[Flow.Publisher](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.Publisher.html)** - \nsource of data  \n* **[Flow.Subscriber](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.Subscriber.html)** - \ndestination of data  \n* **[Flow.Subscription](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.Subscription.html)** - \nmessage control linking a `Flow.Publisher` and `Flow.Subscriber` \n(`Subscriber` signal demand to `Publisher` using `Subscription`)  \n* **[Flow.Processor](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.Processor.html)** - \na component that acts as both a `Subscriber` and `Publisher` (can \nconsume input and produce output).  \n* **[Flow.SubmissionPublisher](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/SubmissionPublisher.html)** - \nthe only one implementation (in `JDK`) of `Flow.Publisher`; has ability to asynchronously issue submitted (non-null) \nitems to current subscribers until it is closed.\n\n## data flow\n\n```\nPUBLISHER -\u003e PROCESSOR -\u003e PROCESSOR -\u003e SUBSCRIBER\n```\n\nWe have two scenarios:  \n\n* `Publisher` is slow, `Subscriber` is fast (best scenario)\n* `Publisher` is fast, `Subscriber` is slow (the `Subscriber` must deal \n\nwith excessive data - the most naive approach is just to drop all \nexcessive data - so the data will be lost)\n\nNote that if we have multiple `subscribers` and one `publisher` - they \nare receiving elements in the same order.\n\n## interaction steps\n\n1. implement `Flow.Publisher` (using, for example `SubmissionPublisher\u003cT\u003e`) and `Flow.Subscriber`\n1. the subscriber attempts to subscribe to the publisher by calling the \n`subscribe(Flow.Subscriber\u003c? super T\u003e subscriber)\n    * take a look at `SubmissionPublisher.subscribe(Subscriber\u003c? super T\u003e subscriber)`\nmethod of the publisher\n    * success: the publisher asynchronously calls the `onSubscribe(Flow.Subscription subscription)` \n    method of the subscriber\n    * failure: `onError(Throwable throwable)` method of the subscriber is called \n    with an `IllegalStateException`, and the interaction ends\n1. the subscriber sends a request to the publisher for `N` items calling the `request(N)` \non the `Subscription`\n1. multiple requests are send regardless if earlier are already fulfilled (non-blocking)\n1. the publisher calls the `onNext(T item)` method of the subscriber and sends an item in each call\n    * if there is no more items to send the publisher calls the `onComplete()` method of the subscriber to signal\nthe end of stream, and interaction ends\n    * note that if subscriber requests `Long.MAX_VALUE` items, the stream becomes not reactive - it is\n    effectively a push stream\n1. if the publisher encounters an error - calls `onError(Throwable throwable)` on subscriber\n1. the subscriber can cancel its subscription by calling the `cancel()` method on its subscription\n    * if a subscription is cancelled, the interaction ends \n    * it is possible for the subscriber to receive items after\n    cancellation if there were pending requests before\n\n## additional remarks\n\nCorrectly `@Override` method `onSubscribe` looks as below:\n\n```\n@Override\npublic void onSubscribe(Flow.Subscription subscription) {\n    if (this.subscription == null) {\n        this.subscription = subscription;\n        this.subscription.request(1); // we handle backpressure through subscription\n    }\n    else {\n        subscription.cancel(); // we handle cancellation through subscription\n    }\n}\n```\n* because we want our `Subscriber` talk to only one `Publisher` - \n`Subscription` represents a link between single `Subscriber` and single \n`Publisher` so you have to cancel the incoming one (if we already have \none, we don't accept any furthers)\n    * think about subscriber as a radio receiver, subscriptions as radio waves, and publisher as radio station\n\n* the actual goal of having them included in the JDK is to provide something called a Service Provider Interface \n(or SPI) layer\n    * this should eventually serve as a unification layer for different components that have reactive \n    and streaming nature, but may expose their own custom APIs, and thus not be able to interoperate with other similar \n    implementations\n\n## tests\n\nWe test it by running:\n\n* `RunAnswer`\n* `RunWorkshop`\n\nthe output should be:\n\n```\nonNext, item: new mapping: 2\nonNext, item: new mapping: 4\nonNext, item: new mapping: 6\nonNext, item: new mapping: 8\nonNext, item: new mapping: 10\nonNext, item: new mapping: 12\n...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fjava12-introduction-to-reactive-programming-workshop/lists"}