forked from mvpjava/java-optional-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOptionalDemo.java
More file actions
256 lines (213 loc) · 10.1 KB
/
OptionalDemo.java
File metadata and controls
256 lines (213 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
package com.mvpjava;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;
/*
Java Optional Demo for ...
"MVP Java" Blog Post www.mvpjava.com Blog Post http://mvpjava.com/java-optional/
and "MVP Java" YouTube Video https://www.youtube.com/c/MVPJava
*/
public class OptionalDemo {
private final Flight flight = new Flight("SAT3455");
private static final int DEFAULT_CONFLICT_ID = -1;
private static final Conflict DEFAULT_CONFLICT = new Conflict(DEFAULT_CONFLICT_ID);
public static void main(String[] args) {
OptionalDemo demo = new OptionalDemo();
// Un-comment one at a time as per tutorial
// demo.theProblem();
// demo.theSolutionInTherory();
// demo.HowToCreateOptionals();
// demo.getValuesOutOfOptionalsUnguarded();
// demo.HowToRetrieveValuesFromOptionalSimpleImperative();
demo.optionalsFunctionalMap();
// demo.getOrElseAlternative();
// demo.getOrElseGetAlternative();
// demo.getOptionalOrDefaultOptional();
// demo.getOrElseThrowAlternative();
//
// demo.listOfOptionals();
// demo.listOfOptionalStreamFlatMap();
}
void theProblem() {
//lets pretend we want the flight to go up to FL 360
int actualFlightLevel = 35000;
flight.setFlightLevel(actualFlightLevel); //current Flight Level (FL)
int requestingFlightLevel = 36000;
if (actualFlightLevel != requestingFlightLevel) {
Conflict conflict = flight.probeForConfictPossiblyReturningNull();
sendToAllDistributedApplications(conflict);
}
}
void theSolutionInTherory() {
//lets pretend we want the flight to go up to FL 360
int actualFlightLevel = 350;
int requestingFlightLevel = 360;
flight.setFlightLevel(actualFlightLevel); //current Flight Level (FL)
if (actualFlightLevel != requestingFlightLevel) {
Optional<Conflict> conflict = flight.probeForConflictReturningOptional();
//commented out to show that cant pass null by accident anymore
//sendToAllDistributedApplications(conflict);
}
}
/* Three ways to create an Optional directly via static factory methods */
void HowToCreateOptionals() {
Conflict nullConflict = null;
Conflict realConflict = new Conflict();
//#1 (try/catch from demo sake)
try {
//Only use Optional.of() if 100% sure reference is not null
Optional<Conflict> conflictOf = Optional.of(nullConflict);
} catch (NullPointerException npe) {
System.out.println("Optional.of() threw NullPointerException because past in null");
}
//#2
//safer, does not throw a NullPointerException if you pass it null
Optional<Conflict> conflictOfNullable = Optional.ofNullable(nullConflict);
//#3
//Sometimes you want to return this from a method instead of null
Optional<Conflict> emptyConflict = Optional.empty();
//DO NOT EVER DO THIS, defeats the entire purpose!!!
//Optional.of(null);
}
/*
Bad because using Optional.get() without checking if first value present.
Might be ok, might not. your taking a chance
*/
void getValuesOutOfOptionalsUnguarded() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional(); //random conflict returned
//try/catch from demo sake
try {
Conflict conflict = optionalConflict.get();
System.out.println("conflict id: " + conflict.getConflictId());
} catch (NoSuchElementException nsee) {
System.out.println("Un-guarded get()...got a NoSuchElementException exception!");
}
}
/*
Without use of Optional, written in the classical if/else == null way.
versus entry level Optonal, imperative way
*/
void HowToRetrieveValuesFromOptionalSimpleImperative() {
//simple, non-Optional way
Conflict conflict = flight.probeForConfictPossiblyReturningNull();
if (conflict != null) {
System.out.println("Conflict detected: " + conflict.getConflictId());
} else {
System.out.println("No Conflict");
}
//versus Optional - imperative way
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();
if (optionalConflict.isPresent()) {
System.out.println("Conflict id: " + optionalConflict.get());
} else {
System.out.println("missing Conflict id");
}
}
/* Now using a function style of programming. The map method
extracts the value of the Optional (if present) as per the
mapper function (lambda/method reference in the case below)and return
an Optional of that value ... Optional<Integer>.
If the Optional value is not present in Optional, map returns an empty Optional .
ifPresentOrElse - Since Java 9
-will execute the "if" portion via its Consumer when the Optional has a value,
-will execute the "Else" portion via a Runnable when Optional has no value
Note: if you don't care for "Else" then just use the ifPresent(Consumer<? super T> action)
*/
void optionalsFunctionalMap() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();
optionalConflict
.map(Conflict::getConflictId)
.ifPresentOrElse(System.out::println,
() -> System.out.println("No Conflicts detected"));
}
//END OF PART 1
/*
.orElse() ALWAYS gets invoked, even if Optional is present.
Possible performance overhead ..maybe, depends on what your creating.
*/
Conflict getOrElseAlternative() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();
Conflict conflict = optionalConflict.orElse(getDefaultConflict());
System.out.println("orElse conflict id: " + conflict.getConflictId());
return conflict;
}
/* Better to use a Supplier for creation of expensive objects.
Now Supplier .. getDefaultConflict() ONLY invoked when Optional is empty
Great for returning a default value
*/
Conflict getOrElseGetAlternative() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();
Conflict conflict = optionalConflict.orElseGet(() -> getDefaultConflict());
System.out.println("orElseGet conflict id: " + conflict.getConflictId());
return conflict;
}
/*
New to Java 9
Uses a Supplier to Produce an "Optional" BUT ONLY IF the Optional is empty.
Not to be confused with orElseGet which has the Supplier return the Value
Great for returning a default Optional
*/
Optional<Conflict> getOptionalOrDefaultOptional() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();//random Conflict
return optionalConflict.or(() -> Optional.of(getDefaultConflict()));
}
/* Exceptions are expensive to create therefore only create them if
Optional is empty with Supplier.
orElseThrow() with NO Supplier (not shown below) will throw a
NoSuchElementException if Optional is empty - since Java 10
*/
Conflict getOrElseThrowAlternative() {
Optional<Conflict> optionalConflict = flight.probeForConflictReturningOptional();//random Conflict
return optionalConflict.orElseThrow(NoConflictException::new); //might throw, random!
}
/*
List of Optional<Conflict>
*/
void listOfOptionals() {
Optional<Conflict> optConflict1 = Optional.of(new Conflict(1));
Optional<Conflict> optConflict2 = Optional.empty();
Optional<Conflict> optConflict3 = Optional.of(new Conflict(2));
List<Optional<Conflict>> listOptConflicts = List.of(optConflict1, optConflict2, optConflict3);
List<Conflict> conflicts
= listOptConflicts.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
conflicts.forEach(System.out::println);
}
/*
flatmap which nicely reduces fiter/map Optional operations with Optional::stream
which was added to Java 9
Will end up with a stream of streams if using just "map" ...
- listOfOptionalConflicts.stream() creates: Stream<Optional<Conflict>>
- if used just "map" would create: Stream<Stream<Conflict>>
- but now with flatMap creates: Stream<Conflict>
Optional::stream ...
- creates a Stream<Conflict> if the Optional value is present
thus replacing isPresent/Get
- creates an empty Stream<> if Optional value is empty
*/
void listOfOptionalStreamFlatMap() {
Conflict nullConflict = null;
Optional<Conflict> optionalc1 = Optional.empty();
Optional<Conflict> optionalc2 = Optional.of(new Conflict());
Optional<Conflict> optionalc3 = Optional.ofNullable(nullConflict);
List<Optional<Conflict>> listOfOptionalConflicts = List.of(optionalc1, optionalc2, optionalc3);
List<Conflict> actualConflicts
= listOfOptionalConflicts.stream() //Stream<Optional<Conflict>>
.flatMap(Optional::stream) //Stream<Conflict>
.collect(Collectors.toList());
actualConflicts.forEach(System.out::println);
}
Conflict getDefaultConflict() {
System.out.println("getDefaultConflict{} has been called");
return DEFAULT_CONFLICT;
}
private void sendToAllDistributedApplications(Conflict conflict) {
//stub just to drive point home
conflict.getConflictId(); //null? possible yes!
}
class NoConflictException extends RuntimeException {
}
}