KEMBAR78
Functional Programming in Java 8 | PDF
Functional Programming
in Java 8
Contents
• Lambda
• Stream
• Parallelization
• Asynchronization
Lambda
Higher-order Function
... is a function that does at least one of the following:
• Takes one or more functions as arguments
• Returns a function as its result
Cache<String, String> cache = CacheBuilder.newBuilder().build();
String sql = "SQL_1";
String result = cache.get(sql, new Callable<String>() {
@Override
public String call() throws Exception {
return "I am the syntax tree of " + sql;
}
}));
What is Lambda Expression?
Lambda is just a syntactic sugar, but it will change how you programing.
Cache<String, String> cache = CacheBuilder.newBuilder().build();
String sql = "SQL_1";
String result = cache.get(sql, new Callable<String>() {
@Override
public String call() throws Exception {
return "I am the syntax tree of " + sql;
}
}));
String result = cache.get(sql, () -> "I am the syntax tree of " + sql);
Closures
• sql is passed to this Callable. How?
Cache<String, String> cache = CacheBuilder.newBuilder().build();
String sql = "SQL_1";
String result = cache.get(sql, new Callable<String>() {
@Override
public String call() throws Exception {
return "I am the syntax tree of " + sql;
}
}));
String result = cache.get(sql, () -> "I am the syntax tree of " + sql);
• How to pass a function along with its context as an argument?
• (extend) How to implement a linked list with Closures?
Objects are poor man's closures.
Closures are poor man's objects.
Closures <=> Objects
Functional Interfaces
• Interfaces with only one abstract method.
• @FunctionalInterface
public interface ActionListener {
public void actionPerformed(ActionEvent event);
}
Logger + Lambda
Logger logger = new Logger();
if (logger.isDebugEnabled()) {
logger.debug("Look at this: " + expensiveOperation());
}
Logger logger = new Logger();
logger.debug(() -> "Look at this: " + expensiveOperation());
function is first class object in Functional Programing
Streams
Example
• Given List<Artist>
• Filter artists living in China
public final class Album {
private String name;
private List<Track> tracks;
private List<Artist> musicians;
}
public final class Artist {
private String name;
private List<Artist> members;
private String nationality;
}
public final class Track {
private final String name;
private final int length;
}
Without streams...
public List<Artist> artistsLivingInLondon() {
List<Artist> results = new ArrayList<>();
for (Artist artist : artists) {
if ("China".equals(artist.getNationality())) {
results.add(artist);
}
}
return results;
}
Example
• Given List<Artist>, filter artists living in China
• Given List<Artist>, return names of all artists
public List<Artist> artistsLivingInChina() {
return artists.stream()
.filter(artist -> "China".equals(artist.getNationality()))
.collect(Collectors.toList());
}
public List<String> getNamesOfArtists_MethodReference() {
return artists.stream()
.map(Artist::getName)
.collect(Collectors.toList());
}
Basic Operations
• map
• filter
• flatMap
• collect
• max/min
Refactoring
Set<String> findLongTracks(List<Album> albums)
Find all long tracks (length >= 60) in a list of albums
public final class Track {
private final String name;
private final int length;
}
Legacy Code
public Set<String> findLongTracks(List<Album> albums) {
Set<String> trackNames = new HashSet<>();
for(Album album : albums) {
for (Track track : album.getTrackList()) {
if (track.getLength() > 60) {
String name = track.getName();
trackNames.add(name);
}
}
}
return trackNames;
}
Step 1
public Set<String> findLongTracks(List<Album> albums) {
Set<String> trackNames = new HashSet<>();
albums.stream()
.forEach(album -> {
album.getTracks()
.forEach(track -> {
if (track.getLength() > 60) {
String name = track.getName();
trackNames.add(name);
}
});
});
return trackNames;
}
filter() map()
Step 2
public Set<String> findLongTracks(List<Album> albums) {
Set<String> trackNames = new HashSet<>();
albums.stream()
.forEach(album -> {
album.getTracks()
.filter(track -> track.getLength() > 60)
.map(track -> track.getName())
.forEach(name -> trackNames.add(name));
});
return trackNames;
}
flatMap()
Step 3
public Set<String> findLongTracks(List<Album> albums) {
Set<String> trackNames = new HashSet<>();
albums.stream()
.flatMap(album -> album.getTracks())
.filter(track -> track.getLength() > 60)
.map(track -> track.getName())
.forEach(name -> trackNames.add(name));
return trackNames;
}
Collectors
• toMap
• toList
• toSet
Step 4
public Set<String> findLongTracks(List<Album> albums) {
return albums.stream()
.flatMap(album -> album.getTracks())
.filter(track -> track.getLength() > 60)
.map(track -> track.getName())
.collect(toSet());
}
More Collectors
• counting
• reducing
• partitioningBy
• groupingBy
• joining
• maxBy
• minBy
...
public Map<Artist, Long> numberOfAlbums(Stream<Album> albums) {
return albums.collect(groupingBy(album -> album.getMainMusician(),
counting()));
}
Downstream Collector
public Map<Artist, Integer> numberOfAlbumsDumb(Stream<Album> albums) {
Map<Artist, List<Album>> albumsByArtist
= albums.collect(groupingBy(album -> album.getMainMusician()));
Map<Artist, Integer> numberOfAlbums = new HashMap<>();
for(Entry<Artist, List<Album>> entry : albumsByArtist.entrySet()) {
numberOfAlbums.put(entry.getKey(), entry.getValue().size());
}
return numberOfAlbums;
}
Parallelization
stream.parallel()
public Map<Integer, Double> parallelDiceRolls() {
double fraction = 1.0 / N;
return IntStream.range(0, N)
.mapToObj(twoDiceThrows())
.collect(groupingBy(side -> side, summingDouble(n -> fraction)));
}
private static IntFunction<Integer> twoDiceThrows() {
return i -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
int firstThrow = random.nextInt(1, 7);
int secondThrow = random.nextInt(1, 7);
return firstThrow + secondThrow;
};
}
stream.parallel()
public Map<Integer, Double> parallelDiceRolls() {
double fraction = 1.0 / N;
return IntStream.range(0, N)
.parallel()
.mapToObj(twoDiceThrows())
.collect(groupingBy(side -> side, summingDouble(n -> fraction)));
}
private static IntFunction<Integer> twoDiceThrows() {
return i -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
int firstThrow = random.nextInt(1, 7);
int secondThrow = random.nextInt(1, 7);
return firstThrow + secondThrow;
};
}
ForkJoinPool
class Fibonacci extends RecursiveTask<Long> {
final Long n;
Fibonacci(Long n) {
this.n = n;
}
@Override
public Long compute() {
if (n <= 1)
return n;
Fibonacci f1 = new Fibonacci(n - 1);
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2);
return f2.compute() + f1.join();
}
}
ForkJoinPool
• Design for compute-intensive tasks
• Work stealing algorithm
• No blocking
Asynchronization
Problem of Futurue
• Call future.get() will block current thread
public Album lookupByName(String albumName) {
Future<Credentials> trackLogin = loginTo("track");
Future<Credentials> artistLogin = loginTo("artist");
try {
Future<List<Track>> tracks = lookupTracks(albumName, trackLogin.get());
Future<List<Artist>> artists = lookupArtists(albumName, artistLogin.get());
return new Album(albumName, tracks.get(), artists.get());
} catch (InterruptedException | ExecutionException e) {
throw new AlbumLookupException(e.getCause());
}
}
CompletableFuture
public Album lookupByName(String albumName) {
CompletableFuture<List<Artist>> artistLookup = loginTo("artist")
.thenCompose(artistLogin -> lookupArtists(albumName, artistLogin));
CompletableFuture<List<Track>> trackLookup = loginTo("track")
.thenCompose(trackLogin -> lookupTracks(albumName, trackLogin));
return trackLookup
.thenCombine(artistLookup,
(tracks, artists) -> new Album(albumName, tracks, artists))
.join();
}
Another side...
future.complete(artist);
future.completeExceptionally(new
AlbumLookupException("Cannot find " + name));
private CompletableFuture<List<Track>> lookupTracks(String albumName,
Credentials credentials) {
return CompletableFuture.supplyAsync(() -> {
sleep(1000);
return tracks;
}, service);
}
RxJava
Observable handles a stream of events
A Kind Reminder
• How to make everything functional?
• Pure Function
• Object
• Loop
• What is Curry?
• What is Y-combinator?
.....
Functional
Programming in Java
A Kind Reminder
• The Magic Book - SICP
Thanks!
Q&A

Functional Programming in Java 8

  • 1.
  • 2.
    Contents • Lambda • Stream •Parallelization • Asynchronization
  • 3.
  • 4.
    Higher-order Function ... isa function that does at least one of the following: • Takes one or more functions as arguments • Returns a function as its result Cache<String, String> cache = CacheBuilder.newBuilder().build(); String sql = "SQL_1"; String result = cache.get(sql, new Callable<String>() { @Override public String call() throws Exception { return "I am the syntax tree of " + sql; } }));
  • 5.
    What is LambdaExpression? Lambda is just a syntactic sugar, but it will change how you programing. Cache<String, String> cache = CacheBuilder.newBuilder().build(); String sql = "SQL_1"; String result = cache.get(sql, new Callable<String>() { @Override public String call() throws Exception { return "I am the syntax tree of " + sql; } })); String result = cache.get(sql, () -> "I am the syntax tree of " + sql);
  • 7.
    Closures • sql ispassed to this Callable. How? Cache<String, String> cache = CacheBuilder.newBuilder().build(); String sql = "SQL_1"; String result = cache.get(sql, new Callable<String>() { @Override public String call() throws Exception { return "I am the syntax tree of " + sql; } })); String result = cache.get(sql, () -> "I am the syntax tree of " + sql);
  • 8.
    • How topass a function along with its context as an argument? • (extend) How to implement a linked list with Closures? Objects are poor man's closures. Closures are poor man's objects. Closures <=> Objects
  • 9.
    Functional Interfaces • Interfaceswith only one abstract method. • @FunctionalInterface public interface ActionListener { public void actionPerformed(ActionEvent event); }
  • 10.
    Logger + Lambda Loggerlogger = new Logger(); if (logger.isDebugEnabled()) { logger.debug("Look at this: " + expensiveOperation()); } Logger logger = new Logger(); logger.debug(() -> "Look at this: " + expensiveOperation()); function is first class object in Functional Programing
  • 11.
  • 12.
    Example • Given List<Artist> •Filter artists living in China public final class Album { private String name; private List<Track> tracks; private List<Artist> musicians; } public final class Artist { private String name; private List<Artist> members; private String nationality; } public final class Track { private final String name; private final int length; }
  • 13.
    Without streams... public List<Artist>artistsLivingInLondon() { List<Artist> results = new ArrayList<>(); for (Artist artist : artists) { if ("China".equals(artist.getNationality())) { results.add(artist); } } return results; }
  • 14.
    Example • Given List<Artist>,filter artists living in China • Given List<Artist>, return names of all artists public List<Artist> artistsLivingInChina() { return artists.stream() .filter(artist -> "China".equals(artist.getNationality())) .collect(Collectors.toList()); } public List<String> getNamesOfArtists_MethodReference() { return artists.stream() .map(Artist::getName) .collect(Collectors.toList()); }
  • 15.
    Basic Operations • map •filter • flatMap • collect • max/min
  • 16.
    Refactoring Set<String> findLongTracks(List<Album> albums) Findall long tracks (length >= 60) in a list of albums public final class Track { private final String name; private final int length; }
  • 17.
    Legacy Code public Set<String>findLongTracks(List<Album> albums) { Set<String> trackNames = new HashSet<>(); for(Album album : albums) { for (Track track : album.getTrackList()) { if (track.getLength() > 60) { String name = track.getName(); trackNames.add(name); } } } return trackNames; }
  • 18.
    Step 1 public Set<String>findLongTracks(List<Album> albums) { Set<String> trackNames = new HashSet<>(); albums.stream() .forEach(album -> { album.getTracks() .forEach(track -> { if (track.getLength() > 60) { String name = track.getName(); trackNames.add(name); } }); }); return trackNames; }
  • 19.
  • 20.
    Step 2 public Set<String>findLongTracks(List<Album> albums) { Set<String> trackNames = new HashSet<>(); albums.stream() .forEach(album -> { album.getTracks() .filter(track -> track.getLength() > 60) .map(track -> track.getName()) .forEach(name -> trackNames.add(name)); }); return trackNames; }
  • 21.
  • 22.
    Step 3 public Set<String>findLongTracks(List<Album> albums) { Set<String> trackNames = new HashSet<>(); albums.stream() .flatMap(album -> album.getTracks()) .filter(track -> track.getLength() > 60) .map(track -> track.getName()) .forEach(name -> trackNames.add(name)); return trackNames; }
  • 23.
  • 24.
    Step 4 public Set<String>findLongTracks(List<Album> albums) { return albums.stream() .flatMap(album -> album.getTracks()) .filter(track -> track.getLength() > 60) .map(track -> track.getName()) .collect(toSet()); }
  • 25.
    More Collectors • counting •reducing • partitioningBy • groupingBy • joining • maxBy • minBy ...
  • 26.
    public Map<Artist, Long>numberOfAlbums(Stream<Album> albums) { return albums.collect(groupingBy(album -> album.getMainMusician(), counting())); } Downstream Collector public Map<Artist, Integer> numberOfAlbumsDumb(Stream<Album> albums) { Map<Artist, List<Album>> albumsByArtist = albums.collect(groupingBy(album -> album.getMainMusician())); Map<Artist, Integer> numberOfAlbums = new HashMap<>(); for(Entry<Artist, List<Album>> entry : albumsByArtist.entrySet()) { numberOfAlbums.put(entry.getKey(), entry.getValue().size()); } return numberOfAlbums; }
  • 27.
  • 28.
    stream.parallel() public Map<Integer, Double>parallelDiceRolls() { double fraction = 1.0 / N; return IntStream.range(0, N) .mapToObj(twoDiceThrows()) .collect(groupingBy(side -> side, summingDouble(n -> fraction))); } private static IntFunction<Integer> twoDiceThrows() { return i -> { ThreadLocalRandom random = ThreadLocalRandom.current(); int firstThrow = random.nextInt(1, 7); int secondThrow = random.nextInt(1, 7); return firstThrow + secondThrow; }; }
  • 29.
    stream.parallel() public Map<Integer, Double>parallelDiceRolls() { double fraction = 1.0 / N; return IntStream.range(0, N) .parallel() .mapToObj(twoDiceThrows()) .collect(groupingBy(side -> side, summingDouble(n -> fraction))); } private static IntFunction<Integer> twoDiceThrows() { return i -> { ThreadLocalRandom random = ThreadLocalRandom.current(); int firstThrow = random.nextInt(1, 7); int secondThrow = random.nextInt(1, 7); return firstThrow + secondThrow; }; }
  • 30.
    ForkJoinPool class Fibonacci extendsRecursiveTask<Long> { final Long n; Fibonacci(Long n) { this.n = n; } @Override public Long compute() { if (n <= 1) return n; Fibonacci f1 = new Fibonacci(n - 1); f1.fork(); Fibonacci f2 = new Fibonacci(n - 2); return f2.compute() + f1.join(); } }
  • 31.
    ForkJoinPool • Design forcompute-intensive tasks • Work stealing algorithm • No blocking
  • 32.
  • 33.
    Problem of Futurue •Call future.get() will block current thread
  • 34.
    public Album lookupByName(StringalbumName) { Future<Credentials> trackLogin = loginTo("track"); Future<Credentials> artistLogin = loginTo("artist"); try { Future<List<Track>> tracks = lookupTracks(albumName, trackLogin.get()); Future<List<Artist>> artists = lookupArtists(albumName, artistLogin.get()); return new Album(albumName, tracks.get(), artists.get()); } catch (InterruptedException | ExecutionException e) { throw new AlbumLookupException(e.getCause()); } }
  • 35.
    CompletableFuture public Album lookupByName(StringalbumName) { CompletableFuture<List<Artist>> artistLookup = loginTo("artist") .thenCompose(artistLogin -> lookupArtists(albumName, artistLogin)); CompletableFuture<List<Track>> trackLookup = loginTo("track") .thenCompose(trackLogin -> lookupTracks(albumName, trackLogin)); return trackLookup .thenCombine(artistLookup, (tracks, artists) -> new Album(albumName, tracks, artists)) .join(); }
  • 36.
    Another side... future.complete(artist); future.completeExceptionally(new AlbumLookupException("Cannot find" + name)); private CompletableFuture<List<Track>> lookupTracks(String albumName, Credentials credentials) { return CompletableFuture.supplyAsync(() -> { sleep(1000); return tracks; }, service); }
  • 37.
  • 38.
    A Kind Reminder •How to make everything functional? • Pure Function • Object • Loop • What is Curry? • What is Y-combinator? ..... Functional Programming in Java
  • 39.
    A Kind Reminder •The Magic Book - SICP
  • 40.