What are lambdas?
❖ (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
❖ Functions don’t change external state
$ cat limerick.txt
There was a young lady of Niger
Who smiled as she rode on a tiger.
They returned from the ride
With the lady inside
And a smile on the face of the tiger.
$ cat limerick.txt | tr -cs "[:alpha:]" "n" | awk '{print
length(), $0}' | sort | uniq
1 a
2 as
2 of
2 on
3 And
3 Who
3 she
3 the
3 was
4 They
4 With
4 face
4 from
4 lady
4 ride
4 rode
5 Niger
5 There
5 smile
5 tiger
5 young
6 inside
6 smiled
8 returned
List<String> lines
= Files.readAllLines(Paths.get("./limerick.txt"), Charset.defaultCharset());
Map<Integer, List<String>> wordGroups
= lines.stream()
.map(line -> line.replaceAll("W", "n").split("n"))
.flatMap(Arrays::stream)
.sorted()
.distinct()
.collect(Collectors.groupingBy(String::length));
wordGroups.forEach( (count, words) -> {
words.forEach(word -> System.out.printf("%d %s %n", count, word));
});
1 a
2 as
2 of
2 on
3 And
3 Who
3 she
3 the
3 was
4 They
4 With
4 face
4 from
4 lady
4 ride
4 rode
5 Niger
5 There
5 smile
5 tiger
5 young
6 inside
6 smiled
8 returned
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);
}
Existing APIs are enriched with
lambdas and streams support
Using built-in functional interfaces
Predicate<T> Checks a condition and returns a
boolean value as result
In filter() method in
java.util.stream.Stream
which is used to remove
elements in the stream that
don’t match the givenConsumer<T> Operation that takes an argument
but returns nothing
In forEach() method in
collections and in
java.util.stream.Stream;
this method is used for
traversing all the elements inFunction<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.
Predicate interface
Stream.of("hello", "world")
.filter(str -> str.startsWith("h"))
.forEach(System.out::println);
The filter() method takes a Predicate
as an argument (predicates are
functions that check a condition and
return a boolean value)
Predicate interface
A Predicate<T> “affirms” something as true or
false: it takes an argument of type T, and returns a
boolean value. You can call test() method on a
Predicate object.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
// other methods elided
}
Consumer interface
A Consumer<T> “consumes” something: it takes
an argument (of generic type T) and returns
nothing (void). You can call accept() method on a
Consumer object.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// the default andThen method elided
}
Function interface
A Function<T, R> “operates” on something and
returns something: it takes one argument (of
generic type T) and returns an object (of generic
type R). You can call apply() method on a Function
object.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
// other methods elided
}
Function interface: example
import java.util.Arrays;
import java.util.function.Function;
public class CombineFunctions {
public static void main(String []args) {
Function<String, Integer> parseInt = Integer:: parseInt ;
Function<Integer, Integer> absInt = Math:: abs ;
Function<String, Integer> parseAndAbsInt = parseInt.andThen(absInt);
Arrays.stream("4, -9, 16".split(", "))
.map(parseAndAbsInt)
.forEach(System. out ::println);
}
}
Prints:
4
9
16
Supplier interface
import java.util.stream.Stream;
import java.util.Random;
class GenerateBooleans {
public static void main(String []args) {
Random random = new Random();
Stream.generate(random::nextBoolean)
.limit(2)
.forEach(System.out::println);
}
}
Prints two boolean
values “true” and “false”
in random order
Supplier interface
A Supplier<T> “supplies” takes nothing but
returns something: it has no arguments and
returns an object (of generic type T). You can call
get() method on a Supplier object
@FunctionalInterface
public interface Supplier<T> {
T get();
// no other methods in this interface
}
Supplier interface: example
Supplier<String> currentDateTime = () -> LocalDateTime.now().toString();
System.out.println(currentDateTime.get());
Prints current time:
2015-10-16T12:40:55.164
Summary of built-in interfaces
in java.util.function interface
❖ There are only four core functional interfaces in this package:
Predicate, Consumer, Function, and Supplier.
❖ The rest of the interfaces are primitive versions, binary
versions, and derived interfaces such as UnaryOperator
interface.
❖ These interfaces differ mainly on the signature of the abstract
methods they declare.
❖ You need to choose the suitable functional interface based on
the context and your need.
Java 8 streams (and parallel streams):
Excellent example of applying functional
programming in practice
IntStream.range(1, 6)
You can use range or iterate
factory methods in the
IntStream interface
IntStream.iterate(1, i -> i + 1).limit(5)
1 2 3 4 5
1 4 9 16 25
map(i -> i * i)
IntStream.range(1, 5).map(i -> i * i).forEach(System.out::println);
Using streams instead of imperative for i = 1 to 5, print i * i
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
import java.util.Arrays;
class StringConcatenator {
public static String result = "";
public static void concatStr(String str) {
result = result + " " + str;
}
}
class StringSplitAndConcatenate {
public static void main(String []args) {
String words[] = "the quick brown fox jumps over the lazy dog".split(" ");
Arrays.stream(words).forEach(StringConcatenator::concatStr);
System.out.println(StringConcatenator.result);
}
}
Gives wrong results with
with parallel() call