xlab #1: advantages of functional programming in java 8

64
www.xsolve.pl Agile Software House Advantages of functional programming in Java 8

Upload: xsolve-software-house

Post on 22-Jan-2018

195 views

Category:

Software


0 download

TRANSCRIPT

www.xsolve.plAgile Software House

Advantages of functional programming in Java 8

www.xsolve.plAgile Software House

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

www.xsolve.plAgile Software House

● Concise

● Little “Boilerplate”

Functional Programming in JVM

www.xsolve.plAgile Software House

● Groovy: Closures

● Java 6:

● Java8 - Lambdas!

www.xsolve.plAgile Software House

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

www.xsolve.plAgile Software House

Streams

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 (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 (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 - 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 IO

www.xsolve.plAgile Software House

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

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

www.xsolve.plAgile Software House

You can find our job offers at

xsolve.pl/career

Thank you for your time!

Questions? Marriage offers?

Free lunch?

[email protected]