{"id":16838960,"url":"https://github.com/akarnokd/async-enumerable","last_synced_at":"2025-04-11T06:43:31.052Z","repository":{"id":27847409,"uuid":"115337382","full_name":"akarnokd/async-enumerable","owner":"akarnokd","description":"Prototype Java 9 library based on the asynchronous enumerable concept (where moveNext() returns a task to compose over). ","archived":false,"fork":false,"pushed_at":"2023-01-30T04:03:11.000Z","size":228,"stargazers_count":18,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-25T04:37:20.307Z","etag":null,"topics":["asynchronous","enumerable","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akarnokd.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":"2017-12-25T12:45:36.000Z","updated_at":"2024-04-21T21:08:28.000Z","dependencies_parsed_at":"2023-02-10T13:15:38.688Z","dependency_job_id":null,"html_url":"https://github.com/akarnokd/async-enumerable","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akarnokd%2Fasync-enumerable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akarnokd%2Fasync-enumerable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akarnokd%2Fasync-enumerable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akarnokd%2Fasync-enumerable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akarnokd","download_url":"https://codeload.github.com/akarnokd/async-enumerable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248358549,"owners_count":21090401,"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":["asynchronous","enumerable","java"],"created_at":"2024-10-13T12:27:48.899Z","updated_at":"2025-04-11T06:43:31.021Z","avatar_url":"https://github.com/akarnokd.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# async-enumerable\n\n\u003ca href='https://travis-ci.com/akarnokd/async-enumerable/builds'\u003e\u003cimg src='https://travis-ci.com/akarnokd/async-enumerable.svg?branch=master'\u003e\u003c/a\u003e\n[![codecov.io](http://codecov.io/github/akarnokd/async-enumerable/coverage.svg?branch=master)](http://codecov.io/github/akarnokd/async-enumerable?branch=master)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.akarnokd/async-enumerable.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.github.akarnokd%2C%20async-enumerable)\n\nPrototype Java 9 library based on the asynchronous enumerable concept (where moveNext() returns a task to compose over). \n\n### Gradle\n\n```groovy\ncompile \"com.github.akarnokd:async-enumerable:0.6.0\"\n```\n\n### Getting started\n\nThe main entry point is the `hu.akarnokd.asyncenum.AsyncEnumerable` interface with its static factory methods similar to RxJava:\n\n```java\nAsyncEnumerable\u003cInteger\u003e source = AsyncEnumerable.range(1, 10);\n\nAsyncEnumerable\u003cString\u003e strings = AsyncEnumerable.fromArray(\"a\", \"b\", \"c\", \"d\");\n```\n\n`AsyncEnumerable\u003cT\u003e` is a deferred cold source, which can be synchronous or asynchronous, the \n`enumerator()` has to be called to receive another interface,\n`hu.akarnokd.asyncenum.AsyncEnumerator` to be \"iterated\" over.\n\n```java\nAsyncEnumerator\u003cInteger\u003e enumerator = source.enumerator();\n```\n\nThe `AsyncEnumerator\u003cT\u003e` defines two methods, `moveNext()` and `current()`. Calling `moveNext()` will instruct the\nsource to produce the next value but instead of returning a `false` or `true` immediately, the method returns a\n`java.util.concurrent.CompletionStage\u003cBoolean\u003e` that is completed with `true` if a value is ready and `false` if no\nmore values to be expected. In the `true` case, one can read the current value via `current()`. \n\n(Cancelling a sequence is currently partially supported via the `cancel()` method on `AsyncEnumerator`,\nbut it feels too much Reactive Streams and not like the pre-existing cancellation support in\nother async-enumerable libraries.)\n\n```java\nCompletionStage\u003cBoolean\u003e stage = enumerator.moveNext();\n\nstage.whenComplete((hasValue, error) -\u003e {\n    if (error != null) {\n        error.printStackTrace();\n        return;\n    }\n    \n    if (hasValue) {\n        System.out.println(enumerator.current());\n    } else {\n        System.out.println(\"Empty source!\");\n    }\n})\n```\n\nNote that calling `moveNext()` or `current()` during the time the `CompletionStage` hasn't been terminated is an \nundefined behavior. Calling `moveNext` after the previous `CompletionStage` returned `false` or an exception is\nalso undefined behavior.\n\nTherefore, consuming multiple values via a plain for loop doesn't work; one has to call `moveNext` when the previous\n`CompletionStage` completed with `true` in a recursively looking pattern. Since some `AsyncEnumerable` chains can\nbe synchronous, this leads to `StackOverflowError` if not handled properly. \n\nFor this purpose, the `forEach()` instance method on `AsyncEnumerable` is available, but given an `AsyncEnumerator`, \nthe following consumption pattern can be employed:\n\n```java\nfinal class EnumeratorConsumer\u003cT\u003e extends AtomicInteger implements BiConsumer\u003cBoolean, Throwable\u003e {\n    \n    final AsyncEnumerator\u003cT\u003e enumerator;\n    \n    public EnumeratorConsumer(AsyncEnumerator\u003cT\u003e enumerator) {\n        this.enumerator = enumerator;\n    }\n    \n    @Override\n    public void accept(Boolean hasNext, Throwable error) {\n        if (error != null) {\n            // handle error case\n            return;\n        }\n        if (hasNext) {\n            T value = enumerator.current();\n            // handle current value\n            moveNext();   \n        } else {\n            // handle no more values\n        }\n    }\n    \n    public void moveNext() {\n        if (getAndIncrement() == 0) {\n            do {\n                enumerator.moveNext().whenComplete(this);\n            } while (decrementAndGet() != 0);\n        }\n    }\n}\n\nnew EnumeratorConsumer(source.enumerator()).moveNext();\n```\n\nThis is practically the same queue-drain or trampolining logic used throughout RxJava. It is recommended though\nto use the combinators and operators of `AsyncEnumerable` instead as working with a sequence of `CompletionStage`\ncontinuations, especially when there are multiple active sequences involved as complications.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakarnokd%2Fasync-enumerable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakarnokd%2Fasync-enumerable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakarnokd%2Fasync-enumerable/lists"}