It’s late 2016, so you probably have been using Java 8 goodies for a while: lambdas, Stream, Optional, new date API ‒ stuff which makes Java development much more pleasant. But the question is: do you know these tools well? I bet you said yes, because writing sweet Java 8 code is piece of cake ‒ you’re using efficient, parallel streams and many lambdas, so what could possibly go wrong? Let me put this straight: most probably you’re doing something wrong. In this talk I won’t actually try to prove that you don’t know what you’re doing, on the contrary ‒ I’ll try to help you be a better programmer by pointing out few mistakes you can make when writing Java 8 code (I know that because I made them all). I’ll also discuss couple common misconceptions regarding Stream and Optional and mention missing language features (also if there is a chance to see them in Java 9 or what library should you use instead). Last but not least, I’ll present you a number of lesser-known gems I found in deepest corners of JDK API, which, I hope, will make your life as a software developer a little bit easier.
How AI, OpenAI, and ChatGPT impact business and software.
JDD 2016 - Grzegorz Rozniecki - Java 8 What Could Possibly Go Wrong
1. Java 8
What could possibly go wrong?
Grzegorz Rozniecki (@xaerxess)
October 11, 2016
2. About me
@xaerxess
Important: Images used in this presentation (and the presentation itself) are free to use under Creative Commons Attribution
License.
Code (reviews) addict Open Source advocate
I’m a software engineer who enjoys learning and likes sharing his knowledge. Big GNU/Linux fan and Open
Source Software advocate. I’ve developed software in various languages, including Perl, JavaScript, Java, Python,
PHP and Lisp (and experimented with few others).
● Being a programmer is mostly reading
code, not writing
● You are not your code!
● Freedom is important
● You can read how libraries, languages,
even operating systems are built - and
learn!
● Contribute, it’s easy!
10. Programming styles
Imperative Declarative Functional
The focus is on what
steps the computer
should take rather than
what the computer will
do (ex. C, C++, Java).
The focus is on what
the computer should
do rather than how it
should do it (ex. SQL).
A subset of declarative
languages that has
heavy focus on
recursion.
11. Streams
java.util.stream
Classes in the new java.util.stream package
provide a Stream API to support
functional-style operations on streams of
elements. The Stream API is integrated into
the Collections API, which enables bulk
operations on collections, such as sequential
or parallel map-reduce transformations.
● Sequential
● Parallel
● Unordered?
“
”
12. Parallel streams
Tasks in ForkJoinPool
into smaller pieces
split
new subtasks
fork
computed tasks
join
1 2 3 4
results from pieces
compose
13. Parallel
streams
List<Integer> primes = IntStream
.range(1, 1_000_000)
.parallel()
.filter(PrimesPrint::isPrime)
.collect(toList());
// how many threads is this using?
// how do I configure that?
Defaults
// see ForkJoinPool Javadoc
-Djava.util.concurrent.ForkJoinPool.common.parallelism=4
16. Libraries
jOOL / jOOλ StreamEx Javaslang
● Almost drop-in
replacement
(extension) of
Stream
● Only sequential
● SQL-like collectors
● Adds TupleN,
FunctionN
● More goodies than
in jOOL
● Also parallel and
primitive streams
● Even
MoreCollectors
● Adds TupleN,
FunctionN
● “Go functional”
● Fully functional
library for Java 8+
● Adds functional
collection library
● Adds TupleN,
FunctionN and
much more (vide
currying)
17. Problem
static final ImmutableList<String> DATA = ImmutableList.of("foo", "bar", "baz", "bazinga");
static final String[] ARRAY_DATA = DATA.stream().toArray(String[]::new);
static final Iterable<String> ITERABLE_DATA = DATA;
static final Iterator<String> ITERATOR_DATA = DATA.iterator(); // don't do this at home or work!
How create Stream?
DATA.stream();
Arrays.stream(ARRAY_DATA);
StreamSupport.stream(ITERABLE_DATA.spliterator(), false);
StreamSupport.stream(
Spliterators.spliteratorUnknownSize(ITERATOR_DATA, Spliterator.ORDERED),
false);
18. Solution - jOOL
static final ImmutableList<String> DATA = ImmutableList.of("foo", "bar", "baz", "bazinga");
static final String[] ARRAY_DATA = DATA.stream().toArray(String[]::new);
static final Iterable<String> ITERABLE_DATA = DATA;
static final Iterator<String> ITERATOR_DATA = DATA.iterator(); // don't do this at home or work!
How create Stream?
Seq.seq(DATA);
Seq.seq(ARRAY_DATA);
Seq.seq(ITERABLE_DATA);
Seq.seq(DATA);
19. Solution - jOOL (fixed)
static final ImmutableList<String> DATA = ImmutableList.of("foo", "bar", "baz", "bazinga");
static final String[] ARRAY_DATA = DATA.stream().toArray(String[]::new);
static final Iterable<String> ITERABLE_DATA = DATA;
static final Iterator<String> ITERATOR_DATA = DATA.iterator(); // don't do this at home or work!
How create Stream?
Seq.seq(DATA);
Seq.of(ARRAY_DATA);
Seq.seq(ITERABLE_DATA);
Seq.seq(DATA);
20. We checked exceptions!
Arrays.stream(dir.listFiles()).forEach(file -> {
try {
System.out.println(file.getCanonicalPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
// Ouch, my fingers hurt! All this typing!
});
...especially in streams
Arrays.stream(dir.listFiles())
.map(Unchecked.function(File::getCanonicalPath))
.forEach(System.out::println);
21. Libraries
On a high level: jOOλ
extends/wraps the Java
collections. Javaslang ships with
their own collections.
/ Lukas Eder, creator of jOOL
Which is the best?
I suspect, jOOλ is good for quick
wins, whereas Javaslang is a
strategic decision.
23. Top tip
Remembering
CompletableFuture API
// CompletableFuture<T> future;
public interface Function<T, R> {
R apply(T t);
}
future.thenApply(function) // CompletableFuture<R>
public interface Consumer<T> {
void accept(T t);
}
future.thenAccept(consumer) // CompletableFuture<Void>
+ xxxAsync for custom Executor
24. Date API
java.time
The main API for dates, times, instants, and
durations. (...) They are based on the ISO
calendar system, which is the de facto world
calendar following the proleptic Gregorian
rules. All the classes are immutable and
thread-safe.
“
25. Dates and parsing
String value = "2001-08-22 03:04:05.321 America/Los_Angeles";
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of(value.substring(23, value.length()).trim()))
.with(LocalDateTime.parse(value.substring(0, 23).trim(), TIMESTAMP));
System.out.println(localDateTime); // 2001-08-22T03:04:05.321
Custom format
26. Dates and parsing
private static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter TIME = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
private static final DateTimeFormatter TIMESTAMP_WITH_TIME_ZONE = new DateTimeFormatterBuilder()
.append(DATE)
.appendLiteral(' ')
.append(TIME)
.appendLiteral(' ')
.appendZoneId()
.toFormatter();
String value = "2001-08-22 03:04:05.321 America/Los_Angeles";
LocalDateTime localDateTime = LocalDateTime.parse(value, TIMESTAMP_WITH_TIME_ZONE);
System.out.println(localDateTime); // 2001-08-22T03:04:05.321
DateTimeFormatterBuilder
27. Dates and parsing
private static final DateTimeFormatter TIMESTAMP_WITH_TIME_ZONE = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral(' ')
.appendZoneId()
.toFormatter();
String value = "2001-08-22 03:04:05.321 America/Los_Angeles";
LocalDateTime localDateTime = LocalDateTime.parse(value, TIMESTAMP_WITH_TIME_ZONE);
System.out.println(localDateTime); // 2001-08-22T03:04:05.321
DateTimeFormatterBuilder
28. Duration
// shiny new Duration class!
long durationMillis = 1000L;
TimeUnit unit = TimeUnit.MILLISECONDS;
Duration duration = Duration.of(durationMillis, unit);
What’s wrong with these examples?
// so let's use proper units
Duration duration = Duration.of(2, ChronoUnit.MONTHS);
java.time.temporal.UnsupportedTemporalTypeException: Unit must not have an estimated duration
29. Optional
To be, or not to be… (aka avoiding null)
Sigh, why does everything related to
Optional have to take 300 messages?
”Brian Goetz (2013-10-23 on
lambda-libs-spec-experts)
“
Junior Developer taking advice before starting work on a
legacy project
http://classicprogrammerpaintings.com/
30. Optional
Problems
● OptionalResult
Naming is hard...
● Optional#getOrElseThrowNoSuchElementException()
Naming is hard… again.
● Implements Serializable?
Deliberately not.
● If / else on Optional?
Vide using .get().
● Optional#stream()
Use stream.flatMap(Optional::stream) instead of:
stream.filter(Optional::isPresent).map(Optional::get)
31. Optional
Rules
1. Never, ever, use null for an Optional variable or
return value.
2. Never use Optional.get() unless you can prove
that the Optional is present.
3. Prefer alternatives APIs over Optional.isPresent()
and Optional.get().
4. It’s generally a bad idea to create an Optional
for the specific purpose of chaining methods
from it to get a value.
5. If an Optional chain has a nested Optional chain,
or has an intermediate result of
Optional<Optional<T>>, it’s probably too
complex.
6. Avoid using Optional in fields, method
parameters, and collections.
7. Don’t use an Optional to wrap any collection
type (List, Set, Map). Instead, use an empty
collection to represent the absence of values.