SlideShare a Scribd company logo
1 of 51
Effective Java, 3/e: keepin’ it effective1
Effective Java, Third Ed.
Keepin’ it effective
Joshua Bloch
@joshbloch
InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
effective-java-third-edition
Presented at QCon New York
www.qconnewyork.com
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
Effective Java, 3/e: keepin’ it effective2
Effective Java, 3d Ed. is now available!
• One new chapter
• Fourteen new items
• Two retired items
• All existing Items thoroughly revised
Effective Java, 3/e: keepin’ it effective3
The evolution of Effective Java
• First edition: 2001 – 232 pages
─ Java 4 – original language + anonymous classes,
asserts, and tons of new APIs
• Second edition: 2008 – 315 pages
─ Java 6 – generics, enums, autoboxing, for-each,
varargs, concurrency utils
• Third edition: 2017 – 366 pages
─ Java 9 – lambdas, streams, optionals, default
methods, try-with-resources, modules
Effective Java, 3/e: keepin’ it effective4
Outline
I. Prefer lambdas to anonymous classes (42)
II. Prefer method references to lambdas (43)
III. Favor standard functional interfaces (44)
IV. Use streams judiciously (45)
V. Use caution when making streams parallel (48)
Effective Java, 3/e: keepin’ it effective5
I. Prefer lambdas to anonymous classes
Historically, anonymous classes for function objects
// Best practice as of Java 7
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
Adequate for classic OO design patterns, such
as Strategy and Command
Effective Java, 3/e: keepin’ it effective6
Now there’s a better way
Use a lambda
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
Effective Java, 3/e: keepin’ it effective7
Now there’s a better way
Use a lambda
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
Better still – use comparator construction method
Collections.sort(words, comparingInt(String::length));
Effective Java, 3/e: keepin’ it effective8
Now there’s a better way
Use a lambda
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
Better still – use comparator construction method
Collections.sort(words, comparingInt(String::length));
Even better – also use the sort method on List
words.sort(comparingInt(String::length));
Effective Java, 3/e: keepin’ it effective9
Under the hood – type inference
• When program says:
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
• It means:
Collections.sort(words, (Comparator<String>)
(String s1, String s2) -> Integer.compare(s1.length(),
s2.length()));
• Type inference is magic
─ No one knows the rules but that’s OK
─ Omit types unless they make program clearer
─ Compiler will tell you if it needs help
Effective Java, 3/e: keepin’ it effective10
A caveat regarding type inference
• Inference relies on generic type information
─ e.g., words being declared a List<String>
─ Code won’t compile if words is a raw List!
• Second edition said “don’t use raw types”
─ Penalty was ugly code and needless runtime bugs
• Third edition says it even more strongly
─ Penalty now includes inability to use lambdas properly
• You must understand generics to use lambdas
Effective Java, 3/e: keepin’ it effective11
Remember this old chestnut?
Enum type with constant-specific class bodies and data
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
public abstract double apply(double x, double y);
}
Effective Java, 3/e: keepin’ it effective12
Now there’s a better way
Enum with function object field – impractical sans lambdas
public enum Operation {
PLUS ("+", (x, y) -> x + y),
MINUS ("-", (x, y) -> x - y),
TIMES ("*", (x, y) -> x * y),
DIVIDE("/", (x, y) -> x / y);
private final String symbol;
private final DoubleBinaryOperator op;
Operation(String symbol, DoubleBinaryOperator op) {
this.symbol = symbol;
this.op = op;
}
@Override public String toString() { return symbol; }
public double apply(double x, double y) {
return op.applyAsDouble(x, y);
}
}
Effective Java, 3/e: keepin’ it effective13
Lambda caveats
• Lambdas lack names and documentation
─ They should be self-explanatory
─ They should not exceed a few lines; one is best
• If lambda would be long or complex:
─ Extract it to method and use method reference
─ Or (for enums) use instance-specific class body
• Anonymous classes still have a few uses
─ Lambdas require functional interfaces
─ Lambdas cannot access themselves;
in a lambda, this refers to the enclosing instance
Effective Java, 3/e: keepin’ it effective14
II. Prefer method references to lambdas
• Lambdas are succinct
map.merge(key, 1, (count, incr) -> count + incr);
• But method references can be more so
map.merge(key, 1, Integer::sum);
• The more parameters, the bigger the win
─ But parameter names may provide documentation
─ If you use a lambda, choose param names carefully!
Effective Java, 3/e: keepin’ it effective15
Occasionally, lambdas are more succinct
service.execute(() -> action());
is preferable to
service.execute(GoshThisClassNameIsHumongous::action);
Lambdas can beat function factories too
.flatMap(x -> x);
is preferable to
.flatMap(Function.identity());
Effective Java, 3/e: keepin’ it effective16
Know all five kinds of method references
All are at times preferable to lambdas
Type Example Lambda Equivalent*
Static Integer::parseInt str -> Integer.parseInt(str)
Bound Instant.now()::isAfter Instant then = Instant.now();
t -> then.isAfter(t)
Unbound String::toLowerCase str -> str.toLowerCase()
Class Constructor TreeMap<K,V>::new () -> new TreeMap<K,V>()
Array Constructor int[]::new len -> new int[len]
Effective Java, 3/e: keepin’ it effective17
The bottom line
• (Almost) anything you can do with a method
reference, you can also do with a lambda
• Method references are usually more succinct
• But sometimes lambdas are clearer
• Use your best judgment
─ You can always change your mind
Effective Java, 3/e: keepin’ it effective18
III. Favor standard functional interfaces
Before lambdas, Template Method pattern was common
public class Cache<K,V> extends LinkedHashMap<K,V> {
final int maxSize; // Set by constructor-omitted for brevity
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size() > maxSize;
}
}
Now, Strategy pattern is generally preferable
public LinkedHashMap(EldestEntryRemovalFunction<K,V> fn) { ... }
// Unnecessary functional interface; use standard one instead!
@FunctionalInterface interface EldestEntryRemovalFunction<K,V> {
boolean remove(Map<K,V> map, Map.Entry<K,V> eldest);
}
Map<K,V> cache =
new LinkedHashMap((map, eldestEntry) -> map.size() > maxSize);
Effective Java, 3/e: keepin’ it effective19
Java has 43 standard functional interfaces
Luckily, there is a fair amount of structure
BiConsumer<T,U>
BiFunction<T,U,R>
BinaryOperator<T>
BiPredicate<T,U>
BooleanSupplier
Consumer<T>
DoubleBinaryOperator
DoubleConsumer
DoubleFunction<R>
DoublePredicate
DoubleSupplier
DoubleToIntFunction
DoubleToLongFunction
DoubleUnaryOperator
Function<T,R>
IntBinaryOperator
IntConsumer
IntFunction<R>
IntPredicate
IntSupplier
IntToDoubleFunction
IntToLongFunction
IntUnaryOperator
LongBinaryOperator
LongConsumer
LongFunction<R>
LongPredicate
LongSupplier
LongToDoubleFunction
LongToIntFunction
LongUnaryOperator
ObjDoubleConsumer<T>
ObjIntConsumer<T>
ObjLongConsumer<T>
Predicate<T>
Supplier<T>
ToDoubleBiFunction<T,U>
ToDoubleFunction<T>
ToIntBiFunction<T,U>
ToIntFunction<T>
ToLongBiFunction<T,U>
ToLongFunction<T>
UnaryOperator<T>
Effective Java, 3/e: keepin’ it effective20
The 6 basic standard functional interfaces
Interface Function Signature Example
UnaryOperator<T> T apply(T t) String::toLowerCase
BinaryOperator<T> T apply(T t1, T t2) BigInteger::add
Predicate<T> boolean test(T t) Collection::isEmpty
Function<T,R> R apply(T t) Arrays::asList
Supplier<T> T get() Instant::now
Consumer<T> void accept(T t) System.out::println
Most of the remaining 37 interfaces provide support
for primitive types. Use them or pay the price!
Effective Java, 3/e: keepin’ it effective21
Advantages of using a standard
functional interface
• Makes APIs easier to learn by reducing
conceptual surface area
• Provides interoperability benefits
─ Many SFIs provide useful default methods
─ For example, Predicate provides methods to
combine and negate predicates
• In our LinkedHashMap example:
─ BiPredicate<Map<K,V>, Map.Entry<K,V>>
should be used in place of a
EldestEntryRemovalFunction<K,V>
Effective Java, 3/e: keepin’ it effective22
When shouldn’t you use a standard
functional interface?
• When none of the standard interfaces apply
• But consider Comparator<T>
─ Structurally identical to ToIntBiFunction<T,T>
─ Seems clear that it would have been wrong to use it
─ Why?
Effective Java, 3/e: keepin’ it effective23
What's so special about Comparator?
• Name provides doc every time it’s used in an API
─ And it's used a lot!
• Strong requirements on valid instances
─ Requirements comprise general contract
─ By implementing the interface, you pledge to adhere
• Many useful default methods to combine and
transform instances
─ Six forms of thenComparing, and reversed
Effective Java, 3/e: keepin’ it effective24
Criteria for writing a purpose-built
functional interface
• Interface should share one or more of these
characteristics with Comparator
1. Likely to be commonly used
2. Has a good descriptive name
3. Has a strong contract associated with it
4. Would benefit from default methods
• If you write a functional interface, remember,
it’s an interface!
─ All interfaces require great care (Item 21)
Effective Java, 3/e: keepin’ it effective25
IV. Use streams judiciously
Quick review – What is a stream?
• A bunch of data objects from a collection, array,
input device, etc., for bulk data processing
• Processed by a pipeline
─ A single stream generator (data source)
─ Zero or more intermediate stream operations
─ A single terminal stream operation
• Supports mostly-functional data processing
• Enables painless parallelism
─ Simply replace stream with parallelStream
─ You may or may not see a performance improvement
Effective Java, 3/e: keepin’ it effective26
Example – first twenty Mersenne Primes
Mersenne number is a number of the form 2p − 1
If p is prime, the corresponding Mersenne number may be prime
If it is, it’s a Mersenne prime
static Stream<BigInteger> primes() {
return Stream.iterate(TWO, BigInteger::nextProbablePrime);
}
public static void main(String[] args) {
primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(System.out::println);
}
Effective Java, 3/e: keepin’ it effective27
An iterative program to compute all the
anagram groups in a dictionary
public static void main(String[] args) throws IOException {
File dictionary = new File(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
Map<String, Set<String>> groups = new HashMap<>();
try (Scanner s = new Scanner(dictionary)) { // Item 9
while (s.hasNext()) {
String word = s.next();
groups.computeIfAbsent(alphabetize(word),
(unused) -> new TreeSet<>()).add(word);
}
}
for (Set<String> group : groups.values())
if (group.size() >= minGroupSize)
System.out.println(group.size() + ": " + group);
}
Effective Java, 3/e: keepin’ it effective28
Helper function to alphabetize a word
Word nerds call the result an alphagram
private static String alphabetize(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
Effective Java, 3/e: keepin’ it effective29
Streams gone crazy
Just because you can doesn’t mean you should!
public class Anagrams {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(
groupingBy(word -> word.chars().sorted()
.collect(StringBuilder::new,
(sb, c) -> sb.append((char) c),
StringBuilder::append).toString()))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.map(group -> group.size() + ": " + group)
.forEach(System.out::println);
}
}
}
Effective Java, 3/e: keepin’ it effective30
A happy medium
Tasteful use of streams enhances clarity and conciseness
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(groupingBy(word -> alphabetize(word)))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.forEach(g -> System.out.println(g.size() + ": " + g));
}
}
Effective Java, 3/e: keepin’ it effective31
Why shouldn’t we use streams to
implement alphabetize?
• Streams do not offer direct support for char
• Resulting implementation would have been
─ more difficult to read
─ more difficult to write correctly
─ probably slower
Effective Java, 3/e: keepin’ it effective32
A minipuzzler - what does this print?
"Hello world!".chars()
.forEach(System.out::print);
Effective Java, 3/e: keepin’ it effective33
Puzzler solution
"Hello world!".chars()
.forEach(System.out::print);
Prints 721011081081113211911111410810033
Why does it do this?
Effective Java, 3/e: keepin’ it effective34
Puzzler Explanation
"Hello world!".chars()
.forEach(System.out::print);
Prints 721011081081113211911111410810033
String’s chars method returns an IntStream
Effective Java, 3/e: keepin’ it effective35
How do you fix it?
"Hello world!".chars()
.forEach(x -> System.out.print((char) x));
Now prints Hello world
Moral
Streams only for object ref types, int, long, and double
Minor primitive types are missing
Type inference can be confusing
Avoid using streams for char processing
Effective Java, 3/e: keepin’ it effective36
A conundrum – Cartesian product
Which is better?
// Iterative Cartesian product computation
private static List<Card> newDeck() {
List<Card> result = new ArrayList<>();
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
result.add(new Card(suit, rank));
return result;
}
// Stream-based Cartesian product computation
private static List<Card> newDeck() {
return Stream.of(Suit.values())
.flatMap(suit -> Stream.of(Rank.values())
.map(rank -> new Card(suit, rank)))
.collect(toList());
}
Effective Java, 3/e: keepin’ it effective37
The bottom line
• Streams are great for many things…
─ But they’re not a panacea
• When you first learn streams, you may want to
convert all of your loops. Don’t!
─ It may make your code shorter, but not clearer
• Exercise judgment
─ Properly used, streams increase brevity and clarity
─ Most programs should combine iteration and streams
• It’s not always clear at the outset
─ If you don’t know, take a guess and start hacking
─ If it doesn’t feel right, try the other approach
Effective Java, 3/e: keepin’ it effective38
V. Use caution making streams parallel
Remember our Mersenne primes program?
static Stream<BigInteger> primes() {
return Stream.iterate(TWO, BigInteger::nextProbablePrime);
}
public static void main(String[] args) {
primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(System.out::println);
}
Runs in 12.5s on my quad-core, 8-thread core i7
Effective Java, 3/e: keepin’ it effective39
How fast do you think this program runs?
static Stream<BigInteger> primes() {
return Stream.iterate(TWO, BigInteger::nextProbablePrime);
}
public static void main(String[] args) {
primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
.parallel()
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(System.out::println);
}
Effective Java, 3/e: keepin’ it effective40
How fast do you think this program runs?
static Stream<BigInteger> primes() {
return Stream.iterate(TWO,
BigInteger::nextProbablePrime);
}
public static void main(String[] args) {
primes().map(p ->
TWO.pow(p.intValueExact()).subtract(ONE))
.parallel()
.filter(mersenne -> mersenne.isProbablePrime(50))
.limit(20)
.forEach(System.out::println);
}
Very, very slowly. I gave up after half an hour.
Effective Java, 3/e: keepin’ it effective41
Why did the program run so slowly?
• Streams library has no idea how to parallelize it
─ And the heuristics fail miserably
• In the best case, parallel unlikely to help if:
─ Stream source is Stream.iterate, or
─ Intermediate limit operation is used
• This isn’t the best case
─ Default strategy for limit computes excess elements
─ Each Mersenne prime takes twice as long as last one
• Moral: do not parallelize indiscriminately!
Effective Java, 3/e: keepin’ it effective42
What does parallelize well?
• Arrays, ArrayList, HashMap, HashSet,
ConcurrentHashMap, int and long ranges…
• What do these sources have in common?
─ Predictably splittable
─ Good locality of reference
• Terminal operation also matters
─ Must be quick, or easily parallelizable
─ Best are reductions, e.g., min, max, count, sum
─ Collectors (AKA mutable reductions) not so good
• Intermediate operations matter too
─ Mapping and filtering good, limit bad
Effective Java, 3/e: keepin’ it effective43
Example – number of primes ≤ n, π(n)
static long pi(long n) {
return LongStream.rangeClosed(2, n)
.mapToObj(BigInteger::valueOf)
.filter(i -> i.isProbablePrime(50))
.count();
}
Takes 31s to compute π(108) on my machine
Effective Java, 3/e: keepin’ it effective44
Example – number of primes ≤ n, π(n)
static long pi(long n) {
return LongStream.rangeClosed(2, n)
.parallel()
.mapToObj(BigInteger::valueOf)
.filter(i -> i.isProbablePrime(50))
.count();
}
In parallel, it takes 9.2s, which is 3.7 times as fast!
Effective Java, 3/e: keepin’ it effective45
.parallel() is merely an optimization
• Optimize Judiciously (Item 67)
• Don’t parallelize unless you can prove it
maintains correctness
• Don’t parallelize unless you have a good
reason to believe it will run faster
• Measure performance before and after
Effective Java, 3/e: keepin’ it effective46
Conclusion
• Java is larger and more complex than it once was
• Now a multiparadigm language
• Not just how to use features, but which to use
• Lambdas and streams can be a big win
─ But you must use them judiciously
• With great power comes great responsibility
Effective Java, 3/e: keepin’ it effective47
Ask me anything!
informit.com Promo Codes
• 35% off - BLOCH991
• But check Amazon!
Effective Java, 3/e: keepin’ it effective48
Effective Java, Third Ed.
Keepin’ it effective
Joshua Bloch
@joshbloch
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
effective-java-third-edition

More Related Content

What's hot

Understanding java streams
Understanding java streamsUnderstanding java streams
Understanding java streams
Shahjahan Samoon
 

What's hot (20)

Java - Exception Handling Concepts
Java - Exception Handling ConceptsJava - Exception Handling Concepts
Java - Exception Handling Concepts
 
Introduction to Design Patterns and Singleton
Introduction to Design Patterns and SingletonIntroduction to Design Patterns and Singleton
Introduction to Design Patterns and Singleton
 
Builder pattern
Builder patternBuilder pattern
Builder pattern
 
Introduction to Spring's Dependency Injection
Introduction to Spring's Dependency InjectionIntroduction to Spring's Dependency Injection
Introduction to Spring's Dependency Injection
 
Java Exception handling
Java Exception handlingJava Exception handling
Java Exception handling
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
Factory Design Pattern
Factory Design PatternFactory Design Pattern
Factory Design Pattern
 
Arrays in Java
Arrays in Java Arrays in Java
Arrays in Java
 
The New JavaScript: ES6
The New JavaScript: ES6The New JavaScript: ES6
The New JavaScript: ES6
 
Quick introduction to scala
Quick introduction to scalaQuick introduction to scala
Quick introduction to scala
 
Spring beans
Spring beansSpring beans
Spring beans
 
Java 8 - Features Overview
Java 8 - Features OverviewJava 8 - Features Overview
Java 8 - Features Overview
 
Core java
Core javaCore java
Core java
 
Understanding java streams
Understanding java streamsUnderstanding java streams
Understanding java streams
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agents
 
Core java complete ppt(note)
Core java  complete  ppt(note)Core java  complete  ppt(note)
Core java complete ppt(note)
 
Java
JavaJava
Java
 
Java 9 Features
Java 9 FeaturesJava 9 Features
Java 9 Features
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
 

Similar to Effective Java, Third Edition - Keepin' it Effective

1 Project 2 Introduction - the SeaPort Project seri.docx
1  Project 2 Introduction - the SeaPort Project seri.docx1  Project 2 Introduction - the SeaPort Project seri.docx
1 Project 2 Introduction - the SeaPort Project seri.docx
honey725342
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
Hiroshi Ono
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
Hiroshi Ono
 

Similar to Effective Java, Third Edition - Keepin' it Effective (20)

Lambdas & Streams
Lambdas & StreamsLambdas & Streams
Lambdas & Streams
 
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
Project Lambda: Functional Programming Constructs in Java - Simon Ritter (Ora...
 
Short intro to scala and the play framework
Short intro to scala and the play frameworkShort intro to scala and the play framework
Short intro to scala and the play framework
 
Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009Scala Talk at FOSDEM 2009
Scala Talk at FOSDEM 2009
 
Colloquium Report
Colloquium ReportColloquium Report
Colloquium Report
 
Java 8
Java 8Java 8
Java 8
 
Interface in java By Dheeraj Kumar Singh
Interface in java By Dheeraj Kumar SinghInterface in java By Dheeraj Kumar Singh
Interface in java By Dheeraj Kumar Singh
 
Scala for Java Programmers
Scala for Java ProgrammersScala for Java Programmers
Scala for Java Programmers
 
Improved Developer Productivity In JDK8
Improved Developer Productivity In JDK8Improved Developer Productivity In JDK8
Improved Developer Productivity In JDK8
 
1 Project 2 Introduction - the SeaPort Project seri.docx
1  Project 2 Introduction - the SeaPort Project seri.docx1  Project 2 Introduction - the SeaPort Project seri.docx
1 Project 2 Introduction - the SeaPort Project seri.docx
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
 
scalaliftoff2009.pdf
scalaliftoff2009.pdfscalaliftoff2009.pdf
scalaliftoff2009.pdf
 
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and StreamsIntroduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
 
Functional programming with Scala
Functional programming with ScalaFunctional programming with Scala
Functional programming with Scala
 
Java8: what's new and what's hot
Java8: what's new and what's hotJava8: what's new and what's hot
Java8: what's new and what's hot
 
Functional Programming With Lambdas and Streams in JDK8
 Functional Programming With Lambdas and Streams in JDK8 Functional Programming With Lambdas and Streams in JDK8
Functional Programming With Lambdas and Streams in JDK8
 
NUS Hackers Club Mar 21 - Whats New in JavaSE 8?
NUS Hackers Club Mar 21 - Whats New in JavaSE 8?NUS Hackers Club Mar 21 - Whats New in JavaSE 8?
NUS Hackers Club Mar 21 - Whats New in JavaSE 8?
 
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVMVoxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
 

More from C4Media

More from C4Media (20)

Streaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoStreaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live Video
 
Next Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileNext Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy Mobile
 
Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020
 
Understand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsUnderstand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java Applications
 
Kafka Needs No Keeper
Kafka Needs No KeeperKafka Needs No Keeper
Kafka Needs No Keeper
 
High Performing Teams Act Like Owners
High Performing Teams Act Like OwnersHigh Performing Teams Act Like Owners
High Performing Teams Act Like Owners
 
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaDoes Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
 
Service Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideService Meshes- The Ultimate Guide
Service Meshes- The Ultimate Guide
 
Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CD
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine Learning
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at Speed
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep Systems
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.js
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly Compiler
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix Scale
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's Edge
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home Everywhere
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing For
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data Engineering
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 

Recently uploaded

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 

Effective Java, Third Edition - Keepin' it Effective

  • 1. Effective Java, 3/e: keepin’ it effective1 Effective Java, Third Ed. Keepin’ it effective Joshua Bloch @joshbloch
  • 2. InfoQ.com: News & Community Site • 750,000 unique visitors/month • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • News 15-20 / week • Articles 3-4 / week • Presentations (videos) 12-15 / week • Interviews 2-3 / week • Books 1 / month Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ effective-java-third-edition
  • 3. Presented at QCon New York www.qconnewyork.com Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide
  • 4. Effective Java, 3/e: keepin’ it effective2 Effective Java, 3d Ed. is now available! • One new chapter • Fourteen new items • Two retired items • All existing Items thoroughly revised
  • 5. Effective Java, 3/e: keepin’ it effective3 The evolution of Effective Java • First edition: 2001 – 232 pages ─ Java 4 – original language + anonymous classes, asserts, and tons of new APIs • Second edition: 2008 – 315 pages ─ Java 6 – generics, enums, autoboxing, for-each, varargs, concurrency utils • Third edition: 2017 – 366 pages ─ Java 9 – lambdas, streams, optionals, default methods, try-with-resources, modules
  • 6. Effective Java, 3/e: keepin’ it effective4 Outline I. Prefer lambdas to anonymous classes (42) II. Prefer method references to lambdas (43) III. Favor standard functional interfaces (44) IV. Use streams judiciously (45) V. Use caution when making streams parallel (48)
  • 7. Effective Java, 3/e: keepin’ it effective5 I. Prefer lambdas to anonymous classes Historically, anonymous classes for function objects // Best practice as of Java 7 Collections.sort(words, new Comparator<String>() { public int compare(String s1, String s2) { return Integer.compare(s1.length(), s2.length()); } }); Adequate for classic OO design patterns, such as Strategy and Command
  • 8. Effective Java, 3/e: keepin’ it effective6 Now there’s a better way Use a lambda Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
  • 9. Effective Java, 3/e: keepin’ it effective7 Now there’s a better way Use a lambda Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length())); Better still – use comparator construction method Collections.sort(words, comparingInt(String::length));
  • 10. Effective Java, 3/e: keepin’ it effective8 Now there’s a better way Use a lambda Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length())); Better still – use comparator construction method Collections.sort(words, comparingInt(String::length)); Even better – also use the sort method on List words.sort(comparingInt(String::length));
  • 11. Effective Java, 3/e: keepin’ it effective9 Under the hood – type inference • When program says: Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length())); • It means: Collections.sort(words, (Comparator<String>) (String s1, String s2) -> Integer.compare(s1.length(), s2.length())); • Type inference is magic ─ No one knows the rules but that’s OK ─ Omit types unless they make program clearer ─ Compiler will tell you if it needs help
  • 12. Effective Java, 3/e: keepin’ it effective10 A caveat regarding type inference • Inference relies on generic type information ─ e.g., words being declared a List<String> ─ Code won’t compile if words is a raw List! • Second edition said “don’t use raw types” ─ Penalty was ugly code and needless runtime bugs • Third edition says it even more strongly ─ Penalty now includes inability to use lambdas properly • You must understand generics to use lambdas
  • 13. Effective Java, 3/e: keepin’ it effective11 Remember this old chestnut? Enum type with constant-specific class bodies and data public enum Operation { PLUS("+") { public double apply(double x, double y) { return x + y; } }, MINUS("-") { public double apply(double x, double y) { return x - y; } }, TIMES("*") { public double apply(double x, double y) { return x * y; } }, DIVIDE("/") { public double apply(double x, double y) { return x / y; } }; private final String symbol; Operation(String symbol) { this.symbol = symbol; } @Override public String toString() { return symbol; } public abstract double apply(double x, double y); }
  • 14. Effective Java, 3/e: keepin’ it effective12 Now there’s a better way Enum with function object field – impractical sans lambdas public enum Operation { PLUS ("+", (x, y) -> x + y), MINUS ("-", (x, y) -> x - y), TIMES ("*", (x, y) -> x * y), DIVIDE("/", (x, y) -> x / y); private final String symbol; private final DoubleBinaryOperator op; Operation(String symbol, DoubleBinaryOperator op) { this.symbol = symbol; this.op = op; } @Override public String toString() { return symbol; } public double apply(double x, double y) { return op.applyAsDouble(x, y); } }
  • 15. Effective Java, 3/e: keepin’ it effective13 Lambda caveats • Lambdas lack names and documentation ─ They should be self-explanatory ─ They should not exceed a few lines; one is best • If lambda would be long or complex: ─ Extract it to method and use method reference ─ Or (for enums) use instance-specific class body • Anonymous classes still have a few uses ─ Lambdas require functional interfaces ─ Lambdas cannot access themselves; in a lambda, this refers to the enclosing instance
  • 16. Effective Java, 3/e: keepin’ it effective14 II. Prefer method references to lambdas • Lambdas are succinct map.merge(key, 1, (count, incr) -> count + incr); • But method references can be more so map.merge(key, 1, Integer::sum); • The more parameters, the bigger the win ─ But parameter names may provide documentation ─ If you use a lambda, choose param names carefully!
  • 17. Effective Java, 3/e: keepin’ it effective15 Occasionally, lambdas are more succinct service.execute(() -> action()); is preferable to service.execute(GoshThisClassNameIsHumongous::action); Lambdas can beat function factories too .flatMap(x -> x); is preferable to .flatMap(Function.identity());
  • 18. Effective Java, 3/e: keepin’ it effective16 Know all five kinds of method references All are at times preferable to lambdas Type Example Lambda Equivalent* Static Integer::parseInt str -> Integer.parseInt(str) Bound Instant.now()::isAfter Instant then = Instant.now(); t -> then.isAfter(t) Unbound String::toLowerCase str -> str.toLowerCase() Class Constructor TreeMap<K,V>::new () -> new TreeMap<K,V>() Array Constructor int[]::new len -> new int[len]
  • 19. Effective Java, 3/e: keepin’ it effective17 The bottom line • (Almost) anything you can do with a method reference, you can also do with a lambda • Method references are usually more succinct • But sometimes lambdas are clearer • Use your best judgment ─ You can always change your mind
  • 20. Effective Java, 3/e: keepin’ it effective18 III. Favor standard functional interfaces Before lambdas, Template Method pattern was common public class Cache<K,V> extends LinkedHashMap<K,V> { final int maxSize; // Set by constructor-omitted for brevity protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return size() > maxSize; } } Now, Strategy pattern is generally preferable public LinkedHashMap(EldestEntryRemovalFunction<K,V> fn) { ... } // Unnecessary functional interface; use standard one instead! @FunctionalInterface interface EldestEntryRemovalFunction<K,V> { boolean remove(Map<K,V> map, Map.Entry<K,V> eldest); } Map<K,V> cache = new LinkedHashMap((map, eldestEntry) -> map.size() > maxSize);
  • 21. Effective Java, 3/e: keepin’ it effective19 Java has 43 standard functional interfaces Luckily, there is a fair amount of structure BiConsumer<T,U> BiFunction<T,U,R> BinaryOperator<T> BiPredicate<T,U> BooleanSupplier Consumer<T> DoubleBinaryOperator DoubleConsumer DoubleFunction<R> DoublePredicate DoubleSupplier DoubleToIntFunction DoubleToLongFunction DoubleUnaryOperator Function<T,R> IntBinaryOperator IntConsumer IntFunction<R> IntPredicate IntSupplier IntToDoubleFunction IntToLongFunction IntUnaryOperator LongBinaryOperator LongConsumer LongFunction<R> LongPredicate LongSupplier LongToDoubleFunction LongToIntFunction LongUnaryOperator ObjDoubleConsumer<T> ObjIntConsumer<T> ObjLongConsumer<T> Predicate<T> Supplier<T> ToDoubleBiFunction<T,U> ToDoubleFunction<T> ToIntBiFunction<T,U> ToIntFunction<T> ToLongBiFunction<T,U> ToLongFunction<T> UnaryOperator<T>
  • 22. Effective Java, 3/e: keepin’ it effective20 The 6 basic standard functional interfaces Interface Function Signature Example UnaryOperator<T> T apply(T t) String::toLowerCase BinaryOperator<T> T apply(T t1, T t2) BigInteger::add Predicate<T> boolean test(T t) Collection::isEmpty Function<T,R> R apply(T t) Arrays::asList Supplier<T> T get() Instant::now Consumer<T> void accept(T t) System.out::println Most of the remaining 37 interfaces provide support for primitive types. Use them or pay the price!
  • 23. Effective Java, 3/e: keepin’ it effective21 Advantages of using a standard functional interface • Makes APIs easier to learn by reducing conceptual surface area • Provides interoperability benefits ─ Many SFIs provide useful default methods ─ For example, Predicate provides methods to combine and negate predicates • In our LinkedHashMap example: ─ BiPredicate<Map<K,V>, Map.Entry<K,V>> should be used in place of a EldestEntryRemovalFunction<K,V>
  • 24. Effective Java, 3/e: keepin’ it effective22 When shouldn’t you use a standard functional interface? • When none of the standard interfaces apply • But consider Comparator<T> ─ Structurally identical to ToIntBiFunction<T,T> ─ Seems clear that it would have been wrong to use it ─ Why?
  • 25. Effective Java, 3/e: keepin’ it effective23 What's so special about Comparator? • Name provides doc every time it’s used in an API ─ And it's used a lot! • Strong requirements on valid instances ─ Requirements comprise general contract ─ By implementing the interface, you pledge to adhere • Many useful default methods to combine and transform instances ─ Six forms of thenComparing, and reversed
  • 26. Effective Java, 3/e: keepin’ it effective24 Criteria for writing a purpose-built functional interface • Interface should share one or more of these characteristics with Comparator 1. Likely to be commonly used 2. Has a good descriptive name 3. Has a strong contract associated with it 4. Would benefit from default methods • If you write a functional interface, remember, it’s an interface! ─ All interfaces require great care (Item 21)
  • 27. Effective Java, 3/e: keepin’ it effective25 IV. Use streams judiciously Quick review – What is a stream? • A bunch of data objects from a collection, array, input device, etc., for bulk data processing • Processed by a pipeline ─ A single stream generator (data source) ─ Zero or more intermediate stream operations ─ A single terminal stream operation • Supports mostly-functional data processing • Enables painless parallelism ─ Simply replace stream with parallelStream ─ You may or may not see a performance improvement
  • 28. Effective Java, 3/e: keepin’ it effective26 Example – first twenty Mersenne Primes Mersenne number is a number of the form 2p − 1 If p is prime, the corresponding Mersenne number may be prime If it is, it’s a Mersenne prime static Stream<BigInteger> primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .filter(mersenne -> mersenne.isProbablePrime(50)) .limit(20) .forEach(System.out::println); }
  • 29. Effective Java, 3/e: keepin’ it effective27 An iterative program to compute all the anagram groups in a dictionary public static void main(String[] args) throws IOException { File dictionary = new File(args[0]); int minGroupSize = Integer.parseInt(args[1]); Map<String, Set<String>> groups = new HashMap<>(); try (Scanner s = new Scanner(dictionary)) { // Item 9 while (s.hasNext()) { String word = s.next(); groups.computeIfAbsent(alphabetize(word), (unused) -> new TreeSet<>()).add(word); } } for (Set<String> group : groups.values()) if (group.size() >= minGroupSize) System.out.println(group.size() + ": " + group); }
  • 30. Effective Java, 3/e: keepin’ it effective28 Helper function to alphabetize a word Word nerds call the result an alphagram private static String alphabetize(String s) { char[] a = s.toCharArray(); Arrays.sort(a); return new String(a); }
  • 31. Effective Java, 3/e: keepin’ it effective29 Streams gone crazy Just because you can doesn’t mean you should! public class Anagrams { public static void main(String[] args) throws IOException { Path dictionary = Paths.get(args[0]); int minGroupSize = Integer.parseInt(args[1]); try (Stream<String> words = Files.lines(dictionary)) { words.collect( groupingBy(word -> word.chars().sorted() .collect(StringBuilder::new, (sb, c) -> sb.append((char) c), StringBuilder::append).toString())) .values().stream() .filter(group -> group.size() >= minGroupSize) .map(group -> group.size() + ": " + group) .forEach(System.out::println); } } }
  • 32. Effective Java, 3/e: keepin’ it effective30 A happy medium Tasteful use of streams enhances clarity and conciseness public static void main(String[] args) throws IOException { Path dictionary = Paths.get(args[0]); int minGroupSize = Integer.parseInt(args[1]); try (Stream<String> words = Files.lines(dictionary)) { words.collect(groupingBy(word -> alphabetize(word))) .values().stream() .filter(group -> group.size() >= minGroupSize) .forEach(g -> System.out.println(g.size() + ": " + g)); } }
  • 33. Effective Java, 3/e: keepin’ it effective31 Why shouldn’t we use streams to implement alphabetize? • Streams do not offer direct support for char • Resulting implementation would have been ─ more difficult to read ─ more difficult to write correctly ─ probably slower
  • 34. Effective Java, 3/e: keepin’ it effective32 A minipuzzler - what does this print? "Hello world!".chars() .forEach(System.out::print);
  • 35. Effective Java, 3/e: keepin’ it effective33 Puzzler solution "Hello world!".chars() .forEach(System.out::print); Prints 721011081081113211911111410810033 Why does it do this?
  • 36. Effective Java, 3/e: keepin’ it effective34 Puzzler Explanation "Hello world!".chars() .forEach(System.out::print); Prints 721011081081113211911111410810033 String’s chars method returns an IntStream
  • 37. Effective Java, 3/e: keepin’ it effective35 How do you fix it? "Hello world!".chars() .forEach(x -> System.out.print((char) x)); Now prints Hello world Moral Streams only for object ref types, int, long, and double Minor primitive types are missing Type inference can be confusing Avoid using streams for char processing
  • 38. Effective Java, 3/e: keepin’ it effective36 A conundrum – Cartesian product Which is better? // Iterative Cartesian product computation private static List<Card> newDeck() { List<Card> result = new ArrayList<>(); for (Suit suit : Suit.values()) for (Rank rank : Rank.values()) result.add(new Card(suit, rank)); return result; } // Stream-based Cartesian product computation private static List<Card> newDeck() { return Stream.of(Suit.values()) .flatMap(suit -> Stream.of(Rank.values()) .map(rank -> new Card(suit, rank))) .collect(toList()); }
  • 39. Effective Java, 3/e: keepin’ it effective37 The bottom line • Streams are great for many things… ─ But they’re not a panacea • When you first learn streams, you may want to convert all of your loops. Don’t! ─ It may make your code shorter, but not clearer • Exercise judgment ─ Properly used, streams increase brevity and clarity ─ Most programs should combine iteration and streams • It’s not always clear at the outset ─ If you don’t know, take a guess and start hacking ─ If it doesn’t feel right, try the other approach
  • 40. Effective Java, 3/e: keepin’ it effective38 V. Use caution making streams parallel Remember our Mersenne primes program? static Stream<BigInteger> primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .filter(mersenne -> mersenne.isProbablePrime(50)) .limit(20) .forEach(System.out::println); } Runs in 12.5s on my quad-core, 8-thread core i7
  • 41. Effective Java, 3/e: keepin’ it effective39 How fast do you think this program runs? static Stream<BigInteger> primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .parallel() .filter(mersenne -> mersenne.isProbablePrime(50)) .limit(20) .forEach(System.out::println); }
  • 42. Effective Java, 3/e: keepin’ it effective40 How fast do you think this program runs? static Stream<BigInteger> primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); } public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) .parallel() .filter(mersenne -> mersenne.isProbablePrime(50)) .limit(20) .forEach(System.out::println); } Very, very slowly. I gave up after half an hour.
  • 43. Effective Java, 3/e: keepin’ it effective41 Why did the program run so slowly? • Streams library has no idea how to parallelize it ─ And the heuristics fail miserably • In the best case, parallel unlikely to help if: ─ Stream source is Stream.iterate, or ─ Intermediate limit operation is used • This isn’t the best case ─ Default strategy for limit computes excess elements ─ Each Mersenne prime takes twice as long as last one • Moral: do not parallelize indiscriminately!
  • 44. Effective Java, 3/e: keepin’ it effective42 What does parallelize well? • Arrays, ArrayList, HashMap, HashSet, ConcurrentHashMap, int and long ranges… • What do these sources have in common? ─ Predictably splittable ─ Good locality of reference • Terminal operation also matters ─ Must be quick, or easily parallelizable ─ Best are reductions, e.g., min, max, count, sum ─ Collectors (AKA mutable reductions) not so good • Intermediate operations matter too ─ Mapping and filtering good, limit bad
  • 45. Effective Java, 3/e: keepin’ it effective43 Example – number of primes ≤ n, π(n) static long pi(long n) { return LongStream.rangeClosed(2, n) .mapToObj(BigInteger::valueOf) .filter(i -> i.isProbablePrime(50)) .count(); } Takes 31s to compute π(108) on my machine
  • 46. Effective Java, 3/e: keepin’ it effective44 Example – number of primes ≤ n, π(n) static long pi(long n) { return LongStream.rangeClosed(2, n) .parallel() .mapToObj(BigInteger::valueOf) .filter(i -> i.isProbablePrime(50)) .count(); } In parallel, it takes 9.2s, which is 3.7 times as fast!
  • 47. Effective Java, 3/e: keepin’ it effective45 .parallel() is merely an optimization • Optimize Judiciously (Item 67) • Don’t parallelize unless you can prove it maintains correctness • Don’t parallelize unless you have a good reason to believe it will run faster • Measure performance before and after
  • 48. Effective Java, 3/e: keepin’ it effective46 Conclusion • Java is larger and more complex than it once was • Now a multiparadigm language • Not just how to use features, but which to use • Lambdas and streams can be a big win ─ But you must use them judiciously • With great power comes great responsibility
  • 49. Effective Java, 3/e: keepin’ it effective47 Ask me anything! informit.com Promo Codes • 35% off - BLOCH991 • But check Amazon!
  • 50. Effective Java, 3/e: keepin’ it effective48 Effective Java, Third Ed. Keepin’ it effective Joshua Bloch @joshbloch
  • 51. Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ effective-java-third-edition