lambdas functions in java 8 - files.meetup.comfiles.meetup.com/19156515/lambdas functions in java...
TRANSCRIPT
Java is evolving…
Lambdas added in Java 8
Java 8 streams (and parallel streams): Excellent example of applying functional
programming in practice
One-liner #1
Files.lines(Paths.get("FileRead.java")).forEach(System.out::println);
This code prints the contents of the file “FileRead.java” in the
current directory
One-liner #2
Pattern.compile(" ").splitAsStream("java 8 streams").forEach(System.out::println);
This code splits the input string “java 8 streams” based on whitespace and hence
prints the strings “java”, “8”, and “streams” on the console
One-liner #3
new Random().ints().limit(5).forEach(System.out::println);
Generates 5 random integers and prints them on the console
One-liner #4
"hello".chars().sorted().forEach(ch -> System.out.printf("%c ", ch));
Extracts characters in the string “hello”, sorts the chars and prints the chars
Productive programming with lambdas
Productive programming with lambdas public static void main(String []file) throws Exception { // process each file passed as argument
// try opening the file with FileReader try (FileReader inputFile = new FileReader(file[0])) { int ch = 0; while( (ch = inputFile.read()) != -1) { // ch is of type int - convert it back to char System.out.print( (char)ch ); } } // try-with-resources will automatically release FileReader object }
public static void main(String []file) throws Exception { Files.lines(Paths.get(file[0])).forEach(System.out::println); }
Functional programming in Java 8
What is different with functional programming?
if
while
for
switch
Perspective - for loops!List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {
System.out.println(string);}
External Iteration
Perspective - for loops!
Arrays.asList("eeny", "meeny", "miny", “mo”) .forEach(string -> System.out.println(string));
Internal Iteration
Perspective - for loops!
Arrays.asList("eeny", "meeny", "miny", “mo”) .forEach(string -> System.out.println(string));
Internal Iteration
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {
System.out.println(string);}
External Iteration
Lambda expression
Perspective - for loops!
Arrays.asList("eeny", "meeny", "miny", “mo”) .forEach(string -> System.out.println(string));
Internal Iteration
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");for(String string : strings) {
System.out.println(string);}
External Iteration
Procedural approach
Functional approach
Let’s get started!
Introducing lambdas
Lambdas
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);
Lambda functions!
Lambdas
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);
Capture in a variable
Execute later
What are lambda functions?
❖ (Java 8) One way to think about lambdas is “anonymous function” or “unnamed function” - they are functions without a name and are not associated with any class
❖ They don’t change external state
What is functional programming?❖ Functional languages view programs as an entity—
called a function—that accepts inputs and produces output
❖ Underlying approach: “Evaluate an expression. Then use the results for something else.”
Composing functions❖ Functions are connected together by their outputs to
other functions’ inputs
sediment pre-carbon ultra-filter post-
carbonFiltered water
Let’s get our hands dirty!
❖ Make sure you have JDK 8 installed
❖ Try out the programs in your machine
❖ You’ll know how to use Java 8 lambdas and functional interfaces after this session
Java 8 lambdas - “Hello world!”
interface LambdaFunction { void call(); }
class FirstLambda { public static void main(String []args) { LambdaFunction lambdaFunction = () -> System.out.println("Hello world"); lambdaFunction.call(); } }
Java 8 lambdas - “Hello world!”
interface LambdaFunction { void call(); }
class FirstLambda { public static void main(String []args) { LambdaFunction lambdaFunction = () -> System.out.println("Hello world"); lambdaFunction.call(); } }
Functional interface - provides signature for lambda functions
Lambda function/expression
Call to the lambda
Prints “Hello world” on the console when executed
Parts of a lambda expression
() -> System.out.println("Hello world");
No parameters, i.e., ()
Arrow operator that separates parameters and the body The lambda body
Return type “void” inferred from the body
Functional interfaces
@FunctionalInterface interface LambdaFunction { void call(); }
Functional interface
Abstract method providing the signature of the lambda function
Annotation to explicitly state that it is a functional interface
Older Single Abstract Methods (SAMs)
// in java.lang package interface Runnable { void run(); }
// in java.util package interface Comparator<T> { boolean compare(T x, T y); }
// java.awt.event package: interface ActionListener { void actionPerformed(ActionEvent e) }
// java.io package interface FileFilter { boolean accept(File pathName); }
Default methods in interfacespublic interface Iterator<E> {
boolean hasNext();
E next();
default void remove() { throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action);
while (hasNext()) action.accept(next());
} }
“Diamond” inheritance problem?
“Diamond” inheritance problem?
interface Interface1 { default public void foo() { System.out.println("Interface1’s foo"); } }
interface Interface2 { default public void foo() { System.out.println("Interface2’s foo"); } }
public class Diamond implements Interface1, Interface2 { public static void main(String []args) { new Diamond().foo(); } }
Error:(9, 8) java: class Diamond inherits unrelated defaults for foo() from types Interface1 and Interface2
“Diamond” inheritance problem?
interface Interface1 { default public void foo() { System.out.println("Interface1’s foo"); } }
interface Interface2 { default public void foo() { System.out.println("Interface2’s foo"); } }
public class Diamond implements Interface1, Interface2 { public void foo() { Interface1.super.foo(); }
public static void main(String []args) { new Diamond().foo(); } }
Add this definition to resolve the
ambiguity
“Diamond” inheritance problem?
class BaseClass { public void foo() { System.out.println("BaseClass’s foo"); } }
interface BaseInterface { default public void foo() { System.out.println("BaseInterface’s foo"); } }
public class Diamond extends BaseClass implements BaseInterface { public static void main(String []args) { new Diamond().foo(); } }
Compiles cleanly; Java 8 rules help deal with the
diamond problem
Using built-in functional interfaces// within Iterable interface default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t);
} }
// in java.util.function package @FunctionalInterface public interface Consumer<T> {
void accept(T t); // the default andThen method elided
}
Using built-in functional interfaces
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); strings.forEach(string -> System.out.println(string));
Built-in interfacesPredicate<T> Checks a condition and returns a
boolean value as resultIn filter() method in java.util.stream.Stream which is used to remove elements in the stream that don’t match the given condition (i.e., predicate) as Consumer<T> Operation that takes an argument but
returns nothingIn forEach() method in collections and in java.util.stream.Stream; this method is used for traversing all the elements in the collection or Function<T,
R>Functions that take an argument and return a result
In map() method in java.util.stream.Stream to transform or operate on the passed value and return a result.
Supplier<T> Operation that returns a value to the caller (the returned value could be same or different values)
In generate() method in java.util.stream.Stream to create a infinite stream of elements.
Built-in interfaces
Method references
Method references - “syntactic sugar” for lambda functions
They “route” function parameters
arg -> System.out.println(arg)
System.out::println
Method references
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = System.out::println; strings.forEach(printString);
Method reference
List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = string -> System.out.println(string); strings.forEach(printString);
Method references
Cannot use method references when lambda functions do more than“routing” function parameters
strings.forEach(string -> System.out.println(string.toUpperCase()));
More processing here than just “routing” parameters
Method references List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo"); Consumer<String> printString = System.out::println; strings.forEach(printString);
public static void printUpperCaseString(String string) { System.out.println(string.toUpperCase()); }
strings.forEach(MethodReference::printUpperCaseString);
“Effectively final” variables
import java.util.Arrays; import java.util.List;
class PigLatin { public static void main(String []args) { String suffix = "ay"; List<String> strings = Arrays.asList("one", "two", "three", "four"); strings.forEach(string -> System.out.println(string + suffix)); } } Accessing “local variable” suffix
here; hence it is considered “effectively final”
“Effectively final” variablesimport java.util.Arrays; import java.util.List;
class PigLatin { public static void main(String []args) { String suffix = "ay"; List<String> strings = Arrays.asList("one", "two", "three", “four");
suffix = "e"; // assign to suffix variable strings.forEach(string -> System.out.println(string + suffix)); } }
PigLatinAssign.java:9: error: local variables referenced from a lambda expression must be final or effectively final strings.forEach(string -> System.out.println(string + suffix)); ^ 1 error
Wrap-up: example using streamsimport java.util.stream.*; import java.nio.file.*; import java.util.*; import java.nio.charset.Charset; import java.io.IOException;
class ReadFile { public static void main(String []args) throws IOException { List<String> lines = Files.readAllLines(Paths.get("./Ulysses.txt"), Charset.defaultCharset()); Map<Integer, List<String>> wordGroups = lines.parallelStream() .map(line -> line.replaceAll("\\W", " ").split(" ")) .flatMap(Arrays::stream) .filter(str -> str.length() > 7) .distinct() .sorted() .collect(Collectors.groupingBy(String::length)); wordGroups.forEach( (count, words) -> { System.out.printf("word(s) of length %d %n", count); words.forEach(System.out::println); }); } }
Lists words organised by their length in the novel
“Ulysses.txt”
Adapt: Learn functional programming
Check out our book!
❖ Programming examples are from our book: ❖ Oracle Certified Professional
Java SE 8 Programmer Exam 1Z0-809: A Comprehensive OCPJP 8 Certification Guide, S.G. Ganesh, Hari Kiran Kumar, Tushar Sharma, Apress, 2016.
❖ Website: ocpjava.wordpress.com
www.designsmells.com bit.ly/sgganesh @GSamarthyam