Introduction
CompletableFuture
is a class in the java.util.concurrent
package that provides a way to write asynchronous, non-blocking code in Java. It is part of the Java 8 enhancements to the Future
interface, which previously provided a way to handle long-running tasks but lacked support for chaining and combining results of multiple asynchronous computations.
Table of Contents
- What is
CompletableFuture
? - Creating a
CompletableFuture
- Running Tasks Asynchronously
- Chaining Tasks
- Combining Multiple
CompletableFuture
s - Handling Errors
- Waiting for Completion
- Example Programs
- Conclusion
1. What is CompletableFuture?
CompletableFuture
is an implementation of the Future
interface that allows you to write asynchronous code. It provides methods for starting, chaining, and combining asynchronous tasks. It can also handle exceptions gracefully, making it used for concurrent programming in Java.
2. Creating a CompletableFuture
You can create a CompletableFuture
instance in several ways:
Example:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
// Creating a CompletableFuture instance
CompletableFuture<String> future = new CompletableFuture<>();
// Completing the CompletableFuture manually
future.complete("Hello, World!");
// Getting the result
try {
System.out.println(future.get()); // Output: Hello, World!
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
Hello, World!
3. Running Tasks Asynchronously
You can run tasks asynchronously using methods like runAsync
and supplyAsync
.
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureAsyncExample {
public static void main(String[] args) {
// Running a task asynchronously
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("Task completed!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// Waiting for the task to complete
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Task completed!
4. Chaining Tasks
You can chain tasks using methods like thenApply
, thenAccept
, and thenRun
.
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureChainingExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Hello";
}).thenApply(result -> {
return result + ", World!";
});
try {
System.out.println(future.get()); // Output: Hello, World!
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Hello, World!
5. Combining Multiple CompletableFutures
You can combine multiple CompletableFuture
s using methods like thenCombine
, thenCompose
, and allOf
.
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureCombiningExample {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
return "World";
});
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
return result1 + " " + result2;
});
try {
System.out.println(combinedFuture.get()); // Output: Hello World
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Hello World
6. Handling Errors
You can handle errors in CompletableFuture
using methods like exceptionally
and handle
.
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureErrorHandlingExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Something went wrong!");
}
return "Hello, World!";
}).exceptionally(ex -> {
return "Error: " + ex.getMessage();
});
try {
System.out.println(future.get()); // Output: Error: Something went wrong!
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Error: Something went wrong!
7. Waiting for Completion
You can wait for the completion of CompletableFuture
using methods like join
, get
, and getNow
.
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureCompletionExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, World!";
});
// Waiting for the future to complete
try {
System.out.println(future.get()); // Output: Hello, World!
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Hello, World!
8. Example Programs
Example 1: Sequential Execution of Asynchronous Tasks
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureSequentialExample {
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("Task 1");
}).thenRunAsync(() -> {
System.out.println("Task 2");
}).thenRunAsync(() -> {
System.out.println("Task 3");
});
// Waiting for all tasks to complete
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Task 1
Task 2
Task 3
Example 2: Combining Results of Multiple Futures
Example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureCombineExample {
public static void main(String[] args) {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
return 10;
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
return 20;
});
CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
return result1 + result2;
});
try {
System.out.println("Combined Result: " + combinedFuture.get()); // Output: Combined Result: 30
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
Output:
Combined Result: 30
9. Conclusion
CompletableFuture
in Java provides a powerful and flexible way to handle asynchronous programming. It allows you to run tasks asynchronously, chain tasks, combine multiple futures, and handle errors gracefully. By understanding and using CompletableFuture
, you can write more efficient and responsive applications.
Happy coding!
Comments
Post a Comment
Leave Comment