{"id":18753007,"url":"https://github.com/spotify/completable-futures","last_synced_at":"2025-05-15T20:03:11.808Z","repository":{"id":5991882,"uuid":"52595362","full_name":"spotify/completable-futures","owner":"spotify","description":"Utilities for working with futures in Java 8","archived":false,"fork":false,"pushed_at":"2023-12-12T12:48:34.000Z","size":1346,"stargazers_count":397,"open_issues_count":4,"forks_count":51,"subscribers_count":101,"default_branch":"master","last_synced_at":"2025-04-08T01:38:13.862Z","etag":null,"topics":["asynchronous","completablefuture-api","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/spotify.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-26T09:56:53.000Z","updated_at":"2025-04-04T13:01:47.000Z","dependencies_parsed_at":"2022-08-06T19:01:03.313Z","dependency_job_id":"ff22b6bc-af89-4eae-bc74-2ea6d350b00a","html_url":"https://github.com/spotify/completable-futures","commit_stats":{"total_commits":128,"total_committers":25,"mean_commits":5.12,"dds":0.6796875,"last_synced_commit":"412966d71135cc0f5e178901c8ef07c01ffecc2e"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fcompletable-futures","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fcompletable-futures/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fcompletable-futures/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fcompletable-futures/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spotify","download_url":"https://codeload.github.com/spotify/completable-futures/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414493,"owners_count":22067271,"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","completablefuture-api","java"],"created_at":"2024-11-07T17:23:42.668Z","updated_at":"2025-05-15T20:03:10.824Z","avatar_url":"https://github.com/spotify.png","language":"Java","funding_links":[],"categories":["并发编程"],"sub_categories":[],"readme":"# completable-futures\n[![Build Status](https://github.com/spotify/completable-futures/actions/workflows/ci.yaml/badge.svg?branch=master)](https://github.com/spotify/completable-futures/actions/workflows/ci.yaml)\n[![Test Coverage](https://img.shields.io/codecov/c/github/spotify/completable-futures/master.svg)](https://codecov.io/github/spotify/completable-futures?branch=master)\n[![Maven Central](https://img.shields.io/maven-central/v/com.spotify/completable-futures.svg)](https://maven-badges.herokuapp.com/maven-central/com.spotify/completable-futures)\n[![License](https://img.shields.io/github/license/spotify/completable-futures.svg)](LICENSE)\n\ncompletable-futures is a set of utility functions to simplify working with asynchronous code in\nJava8.\n\n## Usage\n\nUsing `completable-futures` requires Java 8 but has no additional dependencies. It is meant to be\nincluded as a library in other software. To import it with maven, add this to your pom:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.spotify\u003c/groupId\u003e\n    \u003cartifactId\u003ecompletable-futures\u003c/artifactId\u003e\n    \u003cversion\u003e0.3.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Features\n\n### Combining more than two things\n\nThe builtin CompletableFuture API includes `future.thenCombine(otherFuture, function)` but if you\nwant to combine more than two things it gets trickier. The `CompletableFutures` class contains the\nfollowing APIs to simplify this use-case:\n\n#### allAsList\n\nIf you want to join a list of futures of uniform type, use `allAsList`. This returns a future which\ncompletes to a list of all values of its inputs:\n\n```java\nList\u003cCompletableFuture\u003cString\u003e\u003e futures = asList(completedFuture(\"a\"), completedFuture(\"b\"));\nCompletableFuture\u003cList\u003cString\u003e\u003e joined = CompletableFutures.allAsList(futures);\n```\n\n#### allAsMap\n\nIf you want to join a map of key and value-futures, each of uniform type, use `allAsMap`. This \nreturns a future which completes to a map of all key values of its inputs:\n\n```java\n  Map\u003cString, CompletableFuture\u003cString\u003e\u003e futures = new HashMap() {{\n    put(\"key\", completedFuture(\"value\"));\n  }};\n  CompletableFuture\u003cMap\u003cString, String\u003e\u003e joined = CompletableFutures.allAsMap(futures);\n```\n\n#### successfulAsList\n\nWorks like `allAsList`, but futures that fail will not fail the joined future. Instead, the\ndefaultValueMapper function will be called once for each failed future and value returned will be\nput in the resulting list on the place corresponding to the failed future. The default value\nreturned by the function may be anything, such as `null` or `Optional.empty()`.\n\n```java\nList\u003cCompletableFuture\u003cString\u003e\u003e input = asList(\n    completedFuture(\"a\"),\n    exceptionallyCompletedFuture(new RuntimeException(\"boom\")));\nCompletableFuture\u003cList\u003cString\u003e\u003e joined = CompletableFutures.successfulAsList(input, t -\u003e \"default\");\n```\n\n#### joinList\n\n`joinList` is a stream collector that combines multiple futures into a list. This is handy if you\napply an asynchronous operation to a collection of entities:\n\n```java\ncollection.stream()\n    .map(this::someAsyncFunction)\n    .collect(CompletableFutures.joinList())\n    .thenApply(this::consumeList)\n```\n\n#### joinMap\n\n`joinMap` is a stream collector that applies an asynchronous operation to each element of the \nstream, and associates the result of that operation to a key derived from the original element. \nThis is useful when you need to keep the association between the entity that triggered the \nasynchronous operation and the result of that operation:\n\n```java\ncollection.stream()\n    .collect(joinMap(this::toKey, this::someAsyncFunc))\n    .thenApply(this::consumeMap)\n```\n\n#### combine\n\nIf you want to combine more than two futures of different types, use the `combine` method:\n\n```java\nCompletableFutures.combine(f1, f2, (a, b) -\u003e a + b);\nCompletableFutures.combine(f1, f2, f3, (a, b, c) -\u003e a + b + c);\nCompletableFutures.combine(f1, f2, f3, f4, (a, b, c, d) -\u003e a + b + c + d);\nCompletableFutures.combine(f1, f2, f3, f4, f5, (a, b, c, d, e) -\u003e a + b + c + d + e);\n```\n\n#### combineFutures\n\nIf you want to combine multiple futures into another future, use `combineFutures`:\n\n```java\nCompletableFutures.combineFutures(f1, f2, (a, b) -\u003e completedFuture(a + b));\nCompletableFutures.combineFutures(f1, f2, f3, (a, b, c) -\u003e completedFuture(a + b + c));\nCompletableFutures.combineFutures(f1, f2, f3, f4, (a, b, c, d) -\u003e completedFuture(a + b + c + d));\nCompletableFutures.combineFutures(f1, f2, f3, f4, f5, (a, b, c, d, e) -\u003e completedFuture(a + b + c + d + e));\n```\n\n#### Combine an arbitrary number of futures\n\nIf you want to combine more than six futures of different types, use the other `combine` method.\nSince it supports vararg usage, the function is now the first argument.\nThe `CombinedFutures` object that is input to the function can be used to extract values from the input functions.\n\nThis is effectively the same thing as calling `join()` on the input future, but it's safer because\ncalling `.get(f)` on a future that is not part of the combine, you will get an `IllegalArgumentException`.\n\nThis prevents accidental misuse where you would join on a future that is either not complete, or might never complete\nat all.\n\n```java\nCompletionStage\u003cString\u003e f1;\nCompletionStage\u003cString\u003e f2;\nCompletionStage\u003cString\u003e result = combine(combined -\u003e combined.get(f1) + combined.get(f2), f1, f2);\n```\n\nIf you want to do this in a `combineFutures` form, you can do that like this:\n\n```java\nCompletionStage\u003cString\u003e f1;\nCompletionStage\u003cString\u003e f2;\nCompletionStage\u003cString\u003e result = dereference(combine(combined -\u003e completedFuture(combined.get(f1) + combined.get(f2)), f1, f2));\n```\n\n### Scheduling\n\n#### Polling an external resource\n\nIf you are dealing with a long-running external task that only exposes a polling API, you can\ntransform that into a future like so:\n\n```java\nSupplier\u003cOptional\u003cT\u003e\u003e pollingTask = () -\u003e Optional.ofNullable(resource.result());\nDuration frequency = Duration.ofSeconds(2);\nCompletableFuture\u003cT\u003e result = CompletableFutures.poll(pollingTask, frequency, executor);\n```\n\n### Missing parts of the CompletableFuture API\n\nThe `CompletableFutures` class includes utility functions for operating on futures that is missing\nfrom the builtin API.\n\n#### handleCompose\n\nLike `CompletableFuture.handle` but lets you return a new `CompletionStage` instead of a\ndirect value.\n\n```java\nCompletionStage\u003cString\u003e composed = handleCompose(future, (value, throwable) -\u003e completedFuture(\"hello\"));\n```\n\n#### exceptionallyCompose\n\nLike `CompletableFuture.exceptionally` but lets you return a new `CompletionStage` instead of a\ndirect value.\n\n```java\nCompletionStage\u003cString\u003e composed = CompletableFutures.exceptionallyCompose(future, throwable -\u003e completedFuture(\"fallback\"));\n```\n\n#### dereference\n\nUnwrap a `CompletionStage\u003cCompletionStage\u003cT\u003e\u003e` to a plain `CompletionStage\u003cT\u003e`.\n\n```java\nCompletionStage\u003cCompletionStage\u003cString\u003e\u003e wrapped = completedFuture(completedFuture(\"hello\"));\nCompletionStage\u003cString\u003e unwrapped = CompletableFutures.dereference(wrapped);\n```\n\n#### supplyAsyncCompose\n\nLike `CompletableFuture.supplyAsync` but unwraps a `CompletionStage\u003cCompletionStage\u003cT\u003e\u003e` to a plain `CompletionStage\u003cT\u003e` when\nthe `Supplier` returns a `CompletionStage`.\n\n```java\nCompletionStage\u003cString\u003e suppliedStage = completedFuture(\"hello\").thenApply(stage -\u003e stage + \"-chained\");\nCompletionStage\u003cString\u003e outputStage = CompletableFutures.supplyAsyncCompose(suppliedStage);\n```\n\n#### exceptionallyCompletedFuture\n\nCreates a new future that is already exceptionally completed with the given exception.\n\n```java\nreturn CompletableFutures.exceptionallyCompletedFuture(new RuntimeException(\"boom\"));\n```\n\n## License\n\nCopyright 2016 Spotify AB.\nLicensed under the [Apache License, Version 2.0](LICENSE).\n\n## Code of Conduct\n\nThis project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are\nexpected to honor this code.\n\n## Releases\n\nSee the instructions in [spotify/foss-root][foss-root]\n\n[code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md\n[foss-root]: https://github.com/spotify/foss-root\n\n## Ownership\n\nThe Weaver squad is currently owning this project internally.\nWe are currently in the evaluating process of the ownership of this and other OSS Java libraries.\nThe ownership takes into account **ONLY** security maintenance.\n\nThis repo is also co-owned by other people:\n\n* [mattnworb](https://github.com/mattnworb)\n* [spkrka](https://github.com/spkrka)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fcompletable-futures","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspotify%2Fcompletable-futures","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fcompletable-futures/lists"}