xlab #1: advantages of functional programming in java 8
Post on 22-Jan-2018
196 Views
Preview:
TRANSCRIPT
www.xsolve.plAgile Software House
● 10:00 - 10:25 Welcome!
● 10:30 - 10:40 Functional Programming
● 10:40 - 11:55 Lambdas
● 12:10 - 13:25 Streams
● 13:55 - 15:00 File IO
Agenda
Functional Programming in JVM
www.xsolve.plAgile Software House
● Groovy: Closures
● Java 6:
● Java8 - Lambdas!
// Java 7
button.addActionListener( new ActionListener () { @Override public void actionPerformed(ActionEvent e){ doSomethingWith(e) ; }});
Motivation
www.xsolve.plAgile Software House
// Java 8
button.addActionListener(e -> doSomethingWith(e)) ;
vs
// Java 7
Collections.sort(list, new Comparator<Integer>() { @Overide public int compare(final Integer o1,
final Integer o2) {
return o2.compareTo(o1) ; }});
Motivation
www.xsolve.plAgile Software House
// Java 8
Collections.sort( list, (o1, o2) -> o2.compareTo(o1)) ;
vs
Lambda syntax
www.xsolve.plAgile Software House
new Comparator<String>() { @Override public int compare(final String s1, final String s2) { return s1.length() - s2.length(); }}
(s1, s2) -> {return s1.length() - s2.length();
}
(s1, s2) -> s1.length() - s2.length()
(final String s1, final String s2) -> {return s1.length() - s2.length();
}
(final String s1, final String s2) -> {return s1.length() - s2.length();
}
(final String s1, final String s2) -> {return s1.length() - s2.length();
}
new Comparator<String>() { @Override public int compare(final String s1, final String s2) { return s1.length() - s2.length(); }}
(s1, s2) -> {return s1.length() - s2.length();
}
Sorting Strings by Length
www.xsolve.plAgile Software House
// Java 7 example
Collections.sort(list, new Comparator<String>() {
@Overridepublic int compare(final String s1, final String s2) {
return s1.length() - s2.length() ; }
});
// Java 8 alternative
Collections.sort(list, (s1, s2) -> s1.length() - s2.length()) ;
Lambda syntax (one argument)
www.xsolve.plAgile Software House
(s) -> s.toUpperCase()
() -> doSomething()
s -> s.toUpperCase()
Method references
www.xsolve.plAgile Software House
(args) -> ClassName.staticMethodName( args)
ClassName::staticMethodName
// Examples
Math::cos
Arrays::sort
String::valueOf
String::length
Integer::compareTo
Method references
www.xsolve.plAgile Software House
Method Ref Type Example Equivalent Lambda
SomeClass::staticMethod Math::cos x -> Math.cos(x)
someObject::instanceMethod someString::toUpperCase () -> someString.toUpperCase()
SomeClass::instanceMethod String::toUpperCase s -> s.toUpperCase()
SomeClass::new Employee::new () -> new Employee()
Lambdas with big body
www.xsolve.plAgile Software House
addActionListener(e -> {prepareFuel();/*…*/launch(e);
});
addActionListener(this::fireNuclearRocket);
void fireNuclearRocket(ActionEvent e) {prepareFuel();/*…*/launch(e);
}
Functional interface
www.xsolve.plAgile Software House
@FunctionalInterfaceinterface MyOperation {
String apply(String s); }
String transform(String s, MyOperation mo) { String result = mo.apply(s) ; log(s + " : " + result); return result;} // Java 7
transform("Java8", new MyOperation() { @Override public String apply(String s) { return s.toUpperCase() ; }});
// Java 8transform("Java8", s -> s.toUpperCase()) ;
Simplification 1
www.xsolve.plAgile Software House
transform("Java8", s -> s.toUpperCase()) ; transform("Java8", String::toLowerCase);
transform("Java8", String::toUpperCase) ;
transform("Java8", String::trim);
Simplification 2 (java.util.function)
www.xsolve.plAgile Software House
// before
@FunctionalInterfaceinterface MyOperation {
String apply(String s); }
String transform(String s, MyOperation mo) { String result = mo.apply(s) ; log(s + " : " + result); return result;}
// after
String transform(String s, UnaryOperator<String> uo) { String result = uo.apply(s) ; log(s + "<->" + result); return result;}
java.util.function
www.xsolve.plAgile Software House
INTERFACE METHOD
Consumer<T> void accept(T t)
Supplier<T> T get()
Function<T, R> R apply(T t)
UnaryOperator<T> T apply(T t)
Predicate<T> boolean test(T t)
Lambdas summary
www.xsolve.plAgile Software House
● Lambda syntax: (arg1, arg2) -> arg2.compareTo(arg1)
● Method references: String::length
● @FunctionalInterface
● java.util.function
Streams - motivation
www.xsolve.plAgile Software House
● C / C++ - arrays…
● Java / C# - Collections (List, Set…)
● Java 8 - Streams - Collections taken to another level!
Streams - example
www.xsolve.plAgile Software House
protected List<Book> books = new ArrayList<>();
public void init(){ String tolkien = "J.R.R. Tolkien"; String rowling = "J.K. Rowling"; String norris = "David Norris"; String theGod = "God Almighty";
books.addAll(Arrays.asList( new Book("The Lord of the Rings", tolkien, 1216), new Book("Silmarillion", tolkien, 365), new Book("Harry Potter and the Philosopher's Stone", rowling, 223), new Book("Harry Potter and the Half-Blood Prince", rowling, 554), new Book("Harry Potter and the Deathly Hallows", rowling, 607), new Book("Teach yourself Croatian", norris, 352), new Book("The Bible", theGod, 1200), new Book("The Hobbit", tolkien, 320) ));
TODO: find out● the authors ● of the top-3 ● thickest books● other than the Bible
Streams - example
www.xsolve.plAgile Software House
// 1. filter out the Bible
List<Book> booksFiltered = new ArrayList<>();for (Book book : books){ if (! "The Bible".equals(book.getTitle())) { booksFiltered.add(book); }}
Java7 approach
Streams - example
www.xsolve.plAgile Software House
// 2. sort by number of pages, descending
booksFiltered.sort(new Comparator<Book>() { @Override public int compare(Book o1, Book o2) { return o2.getPages().compareTo(o1.getPages()); }});
Java7 approach
Streams - example
www.xsolve.plAgile Software House
// 3. list the authors
for (int i=0; i<3; i++) { System.out.println(booksFiltered.get(i).getAuthor());}
Java7 approach
Streams - example
www.xsolve.plAgile Software House
books.stream()
.filter(b -> ! "The Bible".equals(b.getTitle()))
.sorted((b1, b2) -> b2.getPages().compareTo(b1.getPages()))
.limit(3)
.map(Book::getAuthor)
.distinct()
.forEach(System.out::println);
Streams to the rescue!
TODO: find out● the authors ● of the top-3 ● thickest books● other than the Bible
Streams - what are they?
www.xsolve.plAgile Software House
● Interface: Stream<String>, Stream<Book>...
● NOT data structures
● Just wrappers around existing data sources (Collections, Files…)
● Do NOT modify the contents of the underlying data sources
● InputStream, ObjectInputStream, FileInputStream
Streams - characteristics
www.xsolve.plAgile Software House
● Easily obtained from arrays or Collections
List aList = new ArrayList();aList.stream();
Collection aCollection = new LinkedHashSet<>();aCollection.stream();
Integer[] anArray = {1, 2, 3, 4, 5};Stream.of(anArray); // Stream<Integer>
Stream.of("Hickory", "Dickory", "Dock");// Stream<String>
aList.stream().filter(o -> o != null);// Stream from another stream!
Chaining!
Streams - characteristics
www.xsolve.plAgile Software House
● Easily obtained from arrays or Collections
● ...and transformed into arrays or Collections
List aList = aStream.collect(Collectors.toList());
Object[] anArray = aStream.toArray();
Streams - characteristics
www.xsolve.plAgile Software House
● Easily obtained from arrays or Collections
● ...and transformed into arrays or Collections
● Designed for Lambdas
aStream .filter(b -> ! "Moby Dick".equals(b.getTitle())) .sorted((b1, b2) ->
b2.getPages().compareTo(b1.getPages())) .map(Book::getAuthor)
Streams - characteristics
www.xsolve.plAgile Software House
● Easily obtained from arrays or Collections
● ...and transformed into arrays or Collections
● Designed for Lambdas
● Lazy (!)
Streams - characteristics
www.xsolve.plAgile Software House
● Easily obtained from arrays or Collections
● ...and transformed into arrays or Collections
● Designed for Lambdas
● Lazy (!)
● Parallelizable (!!!)
bookCollection.parallelStream().forEach(book -> { // do some badass long operation on the book });
bookStream.parallel().forEach(book -> { // do some badass long operation on the book });
Streams - core methods (1/3)
www.xsolve.plAgile Software House
● forEach
void forEach(Consumer)
void forEachOrdered(Consumer)
Stream.of("Facebook", "Google", "xSolve") .forEach(System.out::println);
output?
List<String> list = Arrays.asList("Facebook",
"Google", "xSolve");list.stream().forEach(String::toUpperCase);System.out.println(list);
output?
Stream.of("Facebook", "Google", "xSolve") .forEach(System.out::println).forEach
Stream.of("Facebook", "Google", "xSolve") .forEach(System.out::println);
output:FacebookGooglexSolve
List<String> list = Arrays.asList("Facebook",
"Google", "xSolve");list.stream().forEach(String::toUpperCase);System.out.println(list);
output: [Facebook, Google, xSolve]
Streams - core methods (1/3)
www.xsolve.plAgile Software House
● forEach
void forEach(Consumer)
void forEachOrdered(Consumer)
● map
(mapToDouble, mapToInt, mapToLong)
Stream map(Function mapper)
Stream.of("Facebook", "Google", "xSolve") .map(str -> str.startsWith("x")) .forEach(System.out::println);
output?
int sum = Stream.of("1", "2", "3") .mapToInt(Integer::parseInt) .sum();System.out.println(sum);
output?
Stream.of("Facebook", "Google", "xSolve") .map(str -> str.startsWith("x")) .forEach(System.out::println);
output:falsefalsetrue
int sum = Stream.of("1", "2", "3") .mapToInt(Integer::parseInt) .sum();System.out.println(sum);
output:6
Streams - core methods (1/3)
www.xsolve.plAgile Software House
● forEach
void forEach(Consumer)
void forEachOrdered(Consumer)
● map
(mapToDouble, mapToInt, mapToLong)
Stream map(Function)
● filter
Stream filter(Predicate)
Stream.of("Facebook", "Google", "xSolve") .filter(str -> Character.isLowerCase(str.charAt(0))) .forEach(System.out::println);
output?
Stream.of("Facebook", "Google", "xSolve") .filter(str -> Character.isLowerCase(str.charAt(0))) .forEach(System.out::println);
output: xSolve
Streams - core methods (2/3)
www.xsolve.plAgile Software House
● findFirst
Optional findFirst()
String firstFound = Stream.of("Facebook", "Google", "xSolve")
.filter(str -> str.contains("oo")) .findFirst()
.get();
output?
String notFound = Stream.of("Facebook", "Google", "xSolve")
.filter(str -> str.contains("yay!")) .findFirst() .orElse("404 not found :(");System.out.println(notFound);
output?
String firstFound = Stream.of("Facebook", "Google", "xSolve")
.filter(str -> str.contains("oo")) .findFirst()
.get();
output: Facebook
String notFound = Stream.of("Facebook", "Google", "xSolve")
.filter(str -> str.contains("yay!")) .findFirst() .orElse("404 not found :(");System.out.println(notFound);
output:404 not found :(
Streams - core methods (2/3)
www.xsolve.plAgile Software House
● findFirst
Optional findFirst()
● findAny
Optional findAny()
String anyFound = Stream.of("Facebook", "Google", "xSolve")
.parallel() .findAny() .get();System.out.println(anyFound);
output?
String anyFound = Stream.of("Facebook", "Google", "xSolve")
.parallel() .findAny() .get();System.out.println(anyFound);
output: Facebookor: Googleor: xSolve
Streams - core methods (2/3)
www.xsolve.plAgile Software House
● findFirst
Optional findFirst()
● findAny
Optional findAny()
● collect
collect(Collector collector)
List<String> uppers = Stream.of("cyan", "magenta", "yellow", "black") .map(String::toUpperCase) .collect(Collectors.toList());System.out.println(uppers);
output?
List<String> uppers = Stream.of("cyan", "magenta", "yellow", "black") .map(String::toUpperCase) .collect(Collectors.toList());System.out.println(uppers);
output: [CYAN, MAGENTA, YELLOW, BLACK]
Streams - core methods (2/3)
www.xsolve.plAgile Software House
● findFirst
Optional findFirst()
● findAny
Optional findAny()
● collect
collect(Collector collector)
● toArray
Object[] toArray()
Object[] objArray = Stream.of("cyan", "magenta", "yellow", "black")
.map(String::toUpperCase) .toArray();
String[] strArray = Stream.of("cyan", "magenta", "yellow", "black")
.map(String::toUpperCase) .toArray(String[]::new);
Streams - core methods (3/3)
www.xsolve.plAgile Software House
● Reduce
T reduce(T starter, BinaryOperator)
Optional reduce(BinaryOperator)
String concatStarter = Stream.of("A", "n", "n", "a")
.reduce("Lady ", String::concat);System.out.println(concatStarter);
output?
String concat = Stream.of("A", "n", "n", "a")
.reduce(String::concat) .get();System.out.println(concat);
output?
❏ Stream → single value❏ IntStream – min(), max(),
sum(), average()
String concatStarter = Stream.of("A", "n", "n", "a")
.reduce("Lady ", String::concat);System.out.println(concatStarter);
output: Lady Anna
String concat = Stream.of("A", "n", "n", "a")
.reduce(String::concat) .get();System.out.println(concat);
output: Anna
Streams - core methods (3/3)
www.xsolve.plAgile Software House
● Reduce
T reduce(T starter, BinaryOperator)
Optional reduce(BinaryOperator)
● boolean allMatch(Predicate)
boolean noneMatch(Predicate)
boolean anyMatch(Predicate)
boolean allMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.allMatch(str -> str.endsWith("a"));System.out.println(allMatch);
output?
boolean noneMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.noneMatch(str -> str.endsWith("a"));System.out.println(noneMatch);
output?
boolean anyMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.anyMatch(str -> str.endsWith("a"));System.out.println(anyMatch);
output?
boolean allMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.allMatch(str -> str.endsWith("a"));System.out.println(allMatch);
output: false
boolean noneMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.noneMatch(str -> str.endsWith("a"));System.out.println(noneMatch);
output: false
boolean anyMatch = Stream.of("Veronica", "Anna", "Patricia", "Alan", "Thomas")
.anyMatch(str -> str.endsWith("a"));System.out.println(anyMatch);
output: true
Streams - core methods (3.5/3)
www.xsolve.plAgile Software House
● long count()
● Stream sorted()
● Stream distinct()
● Stream limit(long maxSize)
● Stream skip(long n)
Streams - Terminal vs Non Terminal operations
www.xsolve.plAgile Software House
Terminal
(consume a Stream)
● forEach, forEachOrdered
● toArray, reduce, collect
● min, max, count
● anyMatch, allMatch,
noneMatch
● findFirst, findAny
Non-terminal
(return another Stream)
● map
● filter
● distinct, sorted
● peek
● limit, skip
● parallel, sequential,
unordered
Terminal
(consume a Stream)
● forEach, forEachOrdered
● toArray, reduce, collect
● min, max, count
● anyMatch, allMatch,
noneMatch
● findFirst, findAny
Non-terminal
(return another Stream)
● map
● filter
● distinct, sorted
● peek
● limit, skip
● parallel, sequential,
unordered
Short-circuit operations
Streams - lazy evaluation
www.xsolve.plAgile Software House
books.addAll(Arrays. asList( new Book("The Lord of the Rings" , tolkien, 1216), new Book("Silmarillion" , tolkien, 365), new Book("Harry Potter and something" , rowling, 223), new Book("Harry Potter and blahblah" , rowling, 554)
// + 500k entries));
books.stream() .filter(it -> { System. out.println("name: " + nameFilterCounter ++); return "J.K. Rowling" .equals(it.getAuthor()) ; }) .filter(it -> { System. out.println("\tpages: " + pageFilterCounter ++); return it.getPages() > 500; })
.findFirst() ;
name: 0name: 1name: 2
pages: 0name: 3
pages: 1
books.addAll(Arrays. asList( new Book("The Lord of the Rings" , tolkien, 1216), new Book("Silmarillion" , tolkien, 365), new Book("Harry Potter and something" , rowling, 223), new Book("Harry Potter and blahblah" , rowling, 554)
// + 500k entries));
books.stream() .filter(it -> { System. out.println("name: " + nameFilterCounter ++); return "J.K. Rowling" .equals(it.getAuthor()) ; }) .filter(it -> { System. out.println("\tpages: " + pageFilterCounter ++); return it.getPages() > 500; })
.findFirst(); ← short-circuit operation!
Streams - what you can’t do
www.xsolve.plAgile Software House
● Reuse Stream stream = Stream.of("J", "a", "v", "a");stream.filter(...).map(...)stream.map(...).forEach(...)
Streams - what you can’t do
www.xsolve.plAgile Software House
● Reuse
● Change surrounding local variables
int total = 0;Stream.of("Mercury", "Venus", "Mars") .forEach(str -> { total += str.length(); });
int[] total = {0};Stream.of("Mercury", "Venus", "Mars") .forEach(str -> { total[0] += str.length(); });
...but:
www.xsolve.plAgile Software House
File IOJava6 approach
public void readFile() { File file =
new File("/home/grzegorz/file.txt"); FileInputStream fis = null; try { fis = new FileInputStream(file); int content; while ((content = fis.read()) != -1) { System.out.print((char) content); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }}
www.xsolve.plAgile Software House
File IOJava6 approach
Java7 approach
- java.lang.AutoCloseable
- java.io.Closeable
public void readFile() { File file =
new File("/home/grzegorz/file.txt");
try (FileInputStream fis = new FileInputStream(file)) {
int content; while ((content = fis.read()) != -1) { System.out.print((char) content); } } catch (IOException e) { e.printStackTrace(); }}
public void readFile() { File file =
new File("/home/grzegorz/file.txt"); FileInputStream fis = null; try { fis = new FileInputStream(file); int content; while ((content = fis.read()) != -1) { System.out.print((char) content); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }}
www.xsolve.plAgile Software House
File IO
public void readFile() { Path filePath =
Paths.get("/home/grzegorz/file.txt");
try (Stream<String> stream = Files.lines(filePath)) {
stream.forEach(System.out::print); } catch (IOException e) { e.printStackTrace(); }}
Java8 approach
public void readFile() { File file =
new File("/home/grzegorz/file.txt");
try (FileInputStream fis = new FileInputStream(file)) {
int content; while ((content = fis.read()) != -1) { System.out.print((char) content); } } catch (IOException e) { e.printStackTrace(); }}
Java7 approach
www.xsolve.plAgile Software House
File IO
public void readFile() { File file =
new File("/home/grzegorz/file.txt"); FileInputStream fis = null; try { fis = new FileInputStream(file); int content; while ((content = fis.read()) != -1) { System.out.print((char) content); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }}
Java6 approach
public void readFile() { Path filePath =
Paths.get("/home/grzegorz/file.txt");
try (Stream<String> stream = Files.lines(filePath)) {
stream.forEach(System.out::print); } catch (IOException e) { e.printStackTrace(); }}
Java8 approach
vs.
www.xsolve.plAgile Software House
File IO - Path vs. File
“There is no one-to-one correspondence between the two APIs …”
http://docs.oracle.com/javase/tutorial/essential/io/legacy.html
www.xsolve.plAgile Software House
File IO - How to get Path?
Path p1 = Paths.get("some-file.txt");
Path p2 = Paths.get("C:\MyFolder\another-file.txt");
www.xsolve.plAgile Software House
File IO - Methods of Path class
Methods:
toAbsolutePath, startsWith, endsWith, getFileName, getName,
getNameCount, subpath, getParent, getRoot, normalize, relativize
Sample Method Result
toAbsolutePath C:\eclipse-workspace\java\file-io\input-file.txt
getFileName input-file.tx
getRoot C:\
www.xsolve.plAgile Software House
File IO - File.lines
Stream<String> lines = Files.lines("some-path");
● Can use all the cool and powerful Stream methods.
● Lazy evaluation.
● Throws IOException.
● Stream should be closed.
● Stream implements AutoCloseable
www.xsolve.plAgile Software House
File IO - Example
public List<Car> loadCars(Path filePath) {
try (Stream<String> allCars = Files.lines(filePath)) { return allCars .filter(car -> hasFourSeats(car)) .filter(carWithFourSeats -> this::isRed) .map(redCarWithFourSeats -> addDoors(redCarWithFourSeats)) .sorted() .distinct() .collect(Collectors.toList());
} catch (IOException e) { e.printStackTrace(); }}
www.xsolve.plAgile Software House
File IO - Files.write
Files.write(somePath, lines, someCharset, someOption);
Files.write(somePath, fileArray, someOption);
● somePath to file,
● lines e.g. List<String> lines, bytes[] data
● someCharset e.g. StandardCharsets.UTF_8
● someOption e.q. StandardOpenOption.APPEND
www.xsolve.plAgile Software House
File IO - Files.write
Java7 approach
public void savePoems(List<String> poems) { File file = new File("/home/grzegorz/poems.txt");
try (FileWriter fw = new FileWriter(file)) { for (String poem: poems) { fw.write(poem); } } catch (IOException e) { e.printStackTrace(); }}
www.xsolve.plAgile Software House
File IO - Files.write
Java7 approach
public void savePoems(List<String> poems) { File file = new File("/home/grzegorz/poems.txt");
try (FileWriter fw = new FileWriter(file)) { for (String poem: poems) { fw.write(poem); } } catch (IOException e) { e.printStackTrace(); }}
Java8 approach
public void savePoems(List<String> poems) { Path path = Paths.get("/home/grzegorz/poems.txt");
try { Files.write(path, poems, StandardOpenOption.WRITE); } catch (IOException e) { e.printStackTrace(); }}
www.xsolve.plAgile Software House
● Coreservlets.com, Marty Hall - “Java 8 Tutorial”http://www.coreservlets.com/java-8-tutorial/
● Confitura 2015, Grzegorz Piwowarek - “Lambdas && Monads” (PL)https://youtu.be/VglEyjgxAKY
More on Java8
top related