2929import java .util .concurrent .Executors ;
3030
3131/**
32- *
33- * <p>The Promise object is used for asynchronous computations. A Promise represents an operation that
34- * hasn't completed yet, but is expected in the future.
35- *
36- * <p>A Promise represents a proxy for a value not necessarily known when the promise is created. It
37- * allows you to associate dependent promises to an asynchronous action's eventual success value or
38- * failure reason. This lets asynchronous methods return values like synchronous methods: instead of the final
39- * value, the asynchronous method returns a promise of having a value at some point in the future.
40- *
32+ *
33+ * The Promise object is used for asynchronous computations. A Promise represents an operation
34+ * that hasn't completed yet, but is expected in the future.
35+ *
36+ * <p>A Promise represents a proxy for a value not necessarily known when the promise is created. It
37+ * allows you to associate dependent promises to an asynchronous action's eventual success value or
38+ * failure reason. This lets asynchronous methods return values like synchronous methods: instead
39+ * of the final value, the asynchronous method returns a promise of having a value at some point
40+ * in the future.
41+ *
4142 * <p>Promises provide a few advantages over callback objects:
4243 * <ul>
4344 * <li> Functional composition and error handling
4445 * <li> Prevents callback hell and provides callback aggregation
4546 * </ul>
46- *
47+ *
4748 * <p>
49+ * In this application the usage of promise is demonstrated with two examples:
50+ * <ul>
51+ * <li>Count Lines: In this example a file is downloaded and its line count is calculated.
52+ * The calculated line count is then consumed and printed on console.
53+ * <li>Lowest Character Frequency: In this example a file is downloaded and its lowest frequency
54+ * character is found and printed on console. This happens via a chain of promises, we start with
55+ * a file download promise, then a promise of character frequency, then a promise of lowest frequency
56+ * character which is finally consumed and result is printed on console.
57+ * </ul>
4858 *
4959 * @see CompletableFuture
5060 */
5161public class App {
5262
53- private static final String URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md" ;
63+ private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md" ;
5464 private ExecutorService executor ;
55- private CountDownLatch canStop = new CountDownLatch (2 );
56-
65+ private CountDownLatch stopLatch = new CountDownLatch (2 );
66+
5767 private App () {
5868 executor = Executors .newFixedThreadPool (2 );
5969 }
60-
70+
6171 /**
6272 * Program entry point
6373 * @param args arguments
@@ -67,78 +77,99 @@ private App() {
6777 public static void main (String [] args ) throws InterruptedException , ExecutionException {
6878 App app = new App ();
6979 try {
70- app .run ();
80+ app .promiseUsage ();
7181 } finally {
7282 app .stop ();
7383 }
7484 }
7585
76- private void run () throws InterruptedException , ExecutionException {
77- promiseUsage ();
86+ private void promiseUsage () {
87+ calculateLineCount ();
88+
89+ calculateLowestFrequencyChar ();
7890 }
7991
80- private void promiseUsage () {
81-
82- countLines ()
83- .then (
84- count -> {
85- System .out .println ("Line count is: " + count );
92+ /*
93+ * Calculate the lowest frequency character and when that promise is fulfilled,
94+ * consume the result in a Consumer<Character>
95+ */
96+ private void calculateLowestFrequencyChar () {
97+ lowestFrequencyChar ()
98+ .thenAccept (
99+ charFrequency -> {
100+ System .out .println ("Char with lowest frequency is: " + charFrequency );
86101 taskCompleted ();
87102 }
88103 );
89-
90- lowestCharFrequency ()
91- .then (
92- charFrequency -> {
93- System .out .println ("Char with lowest frequency is: " + charFrequency );
104+ }
105+
106+ /*
107+ * Calculate the line count and when that promise is fulfilled, consume the result
108+ * in a Consumer<Integer>
109+ */
110+ private void calculateLineCount () {
111+ countLines ()
112+ .thenAccept (
113+ count -> {
114+ System .out .println ("Line count is: " + count );
94115 taskCompleted ();
95116 }
96117 );
97118 }
98119
99- private Promise <Character > lowestCharFrequency () {
120+ /*
121+ * Calculate the character frequency of a file and when that promise is fulfilled,
122+ * then promise to apply function to calculate lowest character frequency.
123+ */
124+ private Promise <Character > lowestFrequencyChar () {
100125 return characterFrequency ()
101- .then (
102- charFrequency -> {
103- return Utility .lowestFrequencyChar (charFrequency ).orElse (null );
104- }
105- );
126+ .thenApply (Utility ::lowestFrequencyChar );
106127 }
107128
129+ /*
130+ * Download the file at DEFAULT_URL and when that promise is fulfilled,
131+ * then promise to apply function to calculate character frequency.
132+ */
108133 private Promise <Map <Character , Integer >> characterFrequency () {
109- return download (URL )
110- .then (
111- fileLocation -> {
112- return Utility .characterFrequency (fileLocation );
113- }
114- );
134+ return download (DEFAULT_URL )
135+ .thenApply (Utility ::characterFrequency );
115136 }
116137
138+ /*
139+ * Download the file at DEFAULT_URL and when that promise is fulfilled,
140+ * then promise to apply function to count lines in that file.
141+ */
117142 private Promise <Integer > countLines () {
118- return download (URL )
119- .then (
120- fileLocation -> {
121- return Utility .countLines (fileLocation );
122- }
123- );
143+ return download (DEFAULT_URL )
144+ .thenApply (Utility ::countLines );
124145 }
125146
147+ /*
148+ * Return a promise to provide the local absolute path of the file downloaded in background.
149+ * This is an async method and does not wait until the file is downloaded.
150+ */
126151 private Promise <String > download (String urlString ) {
127152 Promise <String > downloadPromise = new Promise <String >()
128153 .fulfillInAsync (
129154 () -> {
130155 return Utility .downloadFile (urlString );
131- }, executor );
132-
156+ }, executor )
157+ .onError (
158+ throwable -> {
159+ throwable .printStackTrace ();
160+ taskCompleted ();
161+ }
162+ );
163+
133164 return downloadPromise ;
134165 }
135166
136167 private void stop () throws InterruptedException {
137- canStop .await ();
168+ stopLatch .await ();
138169 executor .shutdownNow ();
139170 }
140-
171+
141172 private void taskCompleted () {
142- canStop .countDown ();
173+ stopLatch .countDown ();
143174 }
144175}
0 commit comments