Skip to content

Commit 9520f94

Browse files
committed
Initial commit
0 parents  commit 9520f94

File tree

4 files changed

+364
-0
lines changed

4 files changed

+364
-0
lines changed

src/com/mvpjava/Conflict.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.mvpjava;
2+
3+
import java.util.Random;
4+
5+
public class Conflict {
6+
7+
private final int conflictId;
8+
9+
public Conflict() {
10+
conflictId = new Random().nextInt(101);
11+
}
12+
13+
public Conflict(int conflictId) {
14+
this.conflictId = conflictId;
15+
}
16+
public int getConflictId() {
17+
return conflictId;
18+
}
19+
20+
@Override
21+
public String toString() {
22+
return "Conflict{" + "conflictId=" + conflictId + '}';
23+
}
24+
25+
}

src/com/mvpjava/Flight.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.mvpjava;
2+
3+
import java.util.Optional;
4+
import java.util.Random;
5+
6+
public class Flight {
7+
8+
private final String aircraftID;
9+
private int flightLevel;
10+
private Conflict conflict;
11+
private final Conflict NULL_CONFLICT = new Conflict();
12+
13+
public Flight(String flightID) {
14+
this.aircraftID = flightID;
15+
}
16+
17+
public String getAircraftID() {
18+
return aircraftID;
19+
}
20+
21+
public Optional<Conflict> probeForOptionalConfict() {
22+
conflict = this.probeAirSpace();
23+
return (conflict != null)
24+
? Optional.of(conflict)
25+
: Optional.empty();
26+
}
27+
28+
public Conflict probeForConfictLegacyClassic() {
29+
conflict = this.probeAirSpace();
30+
return (conflict != null)
31+
? (conflict)
32+
: null;
33+
}
34+
35+
@Override
36+
public String toString() {
37+
return "Flight{" + "aircraftID=" + aircraftID + '}';
38+
}
39+
40+
private Conflict probeAirSpace() {
41+
int randomInt = new Random().nextInt(1000);
42+
return (randomInt < 500) ? new Conflict() : null;
43+
}
44+
45+
public int getFlightLevel() {
46+
return flightLevel;
47+
}
48+
49+
public void setFlightLevel(int flightLevel) {
50+
this.flightLevel = flightLevel;
51+
}
52+
53+
54+
55+
}

src/com/mvpjava/OUTLINE

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Java Optional NullPointerException Killer?
2+
==========================================
3+
1. What Problem are we trying to solve?
4+
2. How to create/retrieve an Optional
5+
3. Functional Style
6+
4. Best place to use Java Optional (recommendation)

src/com/mvpjava/OptionalDemo.java

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

0 commit comments

Comments
 (0)