29
29
import java .util .concurrent .Executors ;
30
30
31
31
/**
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
+ *
41
42
* <p>Promises provide a few advantages over callback objects:
42
43
* <ul>
43
44
* <li> Functional composition and error handling
44
45
* <li> Prevents callback hell and provides callback aggregation
45
46
* </ul>
46
- *
47
+ *
47
48
* <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>
48
58
*
49
59
* @see CompletableFuture
50
60
*/
51
61
public class App {
52
62
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" ;
54
64
private ExecutorService executor ;
55
- private CountDownLatch canStop = new CountDownLatch (2 );
56
-
65
+ private CountDownLatch stopLatch = new CountDownLatch (2 );
66
+
57
67
private App () {
58
68
executor = Executors .newFixedThreadPool (2 );
59
69
}
60
-
70
+
61
71
/**
62
72
* Program entry point
63
73
* @param args arguments
@@ -67,78 +77,99 @@ private App() {
67
77
public static void main (String [] args ) throws InterruptedException , ExecutionException {
68
78
App app = new App ();
69
79
try {
70
- app .run ();
80
+ app .promiseUsage ();
71
81
} finally {
72
82
app .stop ();
73
83
}
74
84
}
75
85
76
- private void run () throws InterruptedException , ExecutionException {
77
- promiseUsage ();
86
+ private void promiseUsage () {
87
+ calculateLineCount ();
88
+
89
+ calculateLowestFrequencyChar ();
78
90
}
79
91
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 );
86
101
taskCompleted ();
87
102
}
88
103
);
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 );
94
115
taskCompleted ();
95
116
}
96
117
);
97
118
}
98
119
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 () {
100
125
return characterFrequency ()
101
- .then (
102
- charFrequency -> {
103
- return Utility .lowestFrequencyChar (charFrequency ).orElse (null );
104
- }
105
- );
126
+ .thenApply (Utility ::lowestFrequencyChar );
106
127
}
107
128
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
+ */
108
133
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 );
115
136
}
116
137
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
+ */
117
142
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 );
124
145
}
125
146
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
+ */
126
151
private Promise <String > download (String urlString ) {
127
152
Promise <String > downloadPromise = new Promise <String >()
128
153
.fulfillInAsync (
129
154
() -> {
130
155
return Utility .downloadFile (urlString );
131
- }, executor );
132
-
156
+ }, executor )
157
+ .onError (
158
+ throwable -> {
159
+ throwable .printStackTrace ();
160
+ taskCompleted ();
161
+ }
162
+ );
163
+
133
164
return downloadPromise ;
134
165
}
135
166
136
167
private void stop () throws InterruptedException {
137
- canStop .await ();
168
+ stopLatch .await ();
138
169
executor .shutdownNow ();
139
170
}
140
-
171
+
141
172
private void taskCompleted () {
142
- canStop .countDown ();
173
+ stopLatch .countDown ();
143
174
}
144
175
}
0 commit comments