#onenote# java8

Lambda

Pasted from <http://tutorials.jenkov.com/java/lambda-expressions.html>

 

Java lambda expressions are Java’s first step into functional programming. A Java lambda expression is thus a function which can be created without belonging to any class. A lambda expression can be passed around as if it was an object and executed on demand.

 

In Java 8 you can add an event listener using a Java lambda expression, like this:

StateOwner stateOwner = new StateOwner();

stateOwner.addStateListener(

    (oldState, newState) -> System.out.println(“State changed”)

);

The lambda expressions is this part:

(oldState, newState) -> System.out.println(“State changed”)

 

Matching Lambdas to Interfaces

A single method interface is also sometimes referred to as a functional interface. Matching a Java lambda expression against a functional interface is divided into these steps:

      • Does the interface have only one method?
      • Does the parameters of the lambda expression match the parameters of the single method?
      • Does the return type of the lambda expression match the return type of the single method?

If the answer is yes to these three questions, then the given lambda expression is matched successfully against the interface.

 

Zero Parameters

If the method you are matching your lambda expression against takes no parameters, then you can write your lambda expression like this:

() -> System.out.println(“Zero parameter lambda”);

 

Lambda Function Body

The body of a lambda expression, and thus the body of the function / method it represents, is specified to the right of the -> in the lambda declaration: Here is an example:

(oldState, newState) -> System.out.println(“State changed”)

If your lambda expression needs to consist of multiple lines, you can enclose the lambda function body inside the { } bracket which Java also requires when declaring methods elsewhere. Here is an example:

(oldState, newState) -> {
System.out.println(“Old state: ” + oldState);
System.out.println(“New state: ” + newState);
}

 

Returning a Value From a Lambda Expression

You can return values from Java lambda expressions, just like you can from a method. You just add a return statement to the lambda function body, like this:

(param) -> {
System.out.println(“param: ” + param);
return “return value”;
}

 

In case all your lambda expression is doing is to calculate a return value and return it, you can specify the return value in a shorter way. Instead of this:

(a1, a2) -> { return a1 > a2; }

You can write:

(a1, a2) -> a1 > a2;

 

 

Table 3.3. Examples of lambdas with functional interfaces

Use case Example of lambda Matching functional interface
A boolean expression (List<String> list) -> list.isEmpty() Predicate<List<String>>
Creating objects () -> new Apple(10) Supplier<Apple>
Consuming from an object (Apple a) -> System.out.println(a.getWeight()) Consumer<Apple>
Select/extract from an object (String s) -> s.length() Function<String, Integer> or ToIntFunction<String>
Combine two values (int a, int b) -> a * b IntBinaryOperator
Compare two objects (Apple a1, Apple a2) -> a1.getWeight().compareTo (a2.getWeight()) Comparator<Apple> or BiFunction<Apple, Apple, Integer> or ToIntBiFunction<Apple, Apple>

 

Method references

When you need a method reference, the target reference is placed before the delimiter :: and the name of the method is provided after it. For example, Apple::getWeight is a method reference to the method getWeight defined in the Apple class

Table 3.4. Examples of lambdas and method reference equivalents

Lambda Method reference equivalent
(Apple a) -> a.getWeight() Apple::getWeight
() -> Thread.currentThread().dumpStack() Thread.currentThread()::dumpStack
(str, i) -> str.substring(i) String::substring
(String s) -> System.out.println(s) System.out::println

 

 

Constructor references

You can create a reference to an existing constructor using its name and the keyword new as follows: ClassName::new. It works similarly to a reference to a static method.

 

The Predicate interface includes three methods that let you reuse an existingPredicate to create more complicated ones: negate, and, and or. For example, you can use the method negate to return the negation of aPredicate, such as an apple that is not red:

 

 

Composing Functions

Finally, you can also compose lambda expressions represented by the Function interface. The Function interface comes with two default methods for this, andThen and compose, which both return an instance of Function.

 

andThen

compose

 

 

Figure 3.6. Using andThen vs. compose

 

 

Java 8 comes with a list of common functional interfaces in the java.util .function package, which includes Predicate<T>, Function<T, R>, Supplier<T>, Consumer<T>, and BinaryOperator<T>, described in table 3.2.

Table 3.2. Common functional interfaces in Java 8

Functional interface Function descriptor Primitive specializations
Predicate<T> T -> boolean IntPredicate, LongPredicate, DoublePredicate
Consumer<T> T -> void IntConsumer, LongConsumer, DoubleConsumer
Function<T, R> T -> R IntFunction<R>, IntToDoubleFunction, IntToLongFunction, LongFunction<R>, LongToDoubleFunction, LongToIntFunction, DoubleFunction<R>, ToIntFunction<T>, ToDoubleFunction<T>, ToLongFunction<T>
Supplier<T> () -> T BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier
UnaryOperator<T> T -> T IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator
BinaryOperator<T> (T, T) -> T IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator
BiPredicate<L, R> (L, R) -> boolean  
BiConsumer<T, U> (T, U) -> void ObjIntConsumer<T>, ObjLongConsumer<T>, ObjDoubleConsumer<T>
BiFunction<T, U, R> (T, U) -> R ToIntBiFunction<T, U>, ToLongBiFunction<T, U>, ToDoubleBiFunction<T, U>

 

There are primitive specializations of common generic functional interfaces such as Predicate<T> and Function<T, R> that can be used to avoid boxing operations: IntPredicate, IntToLongFunction, and so on.

 

 

    • Functional interfaces such as Comparator, Predicate, and Function have several default methods that can be used to combine lambda expressions.

 

Steams

Pasted from <http://www.tutorialspoint.com/java8/java8_streams.htm>

 Java 8 introduced the concept of stream that lets the developer to process data declaratively and leverage multicore architecture without the need to write any specific code for it.

What is Stream?

Stream represents a sequence of objects from a source, which supports aggregate operations. Following are the characteristics of a Stream

  • Sequence of elements  A stream provides a set of elements of specific type in a sequential manner. A stream gets/computes elements on demand. It never stores the elements.
  • Source  Stream takes Collections, Arrays, or I/O resources as input source.
  • Aggregate operations  Stream supports aggregate operations like filter, map, limit, reduce, find, match, and so on.
  • Pipelining  Most of the stream operations return stream itself so that their result can be pipelined. These operations are called intermediate operations and their function is to take input, process them, and return output to the target. collect() method is a terminal operation which is normally present at the end of the pipelining operation to mark the end of the stream.
  • Automatic iterations  Stream operations do the iterations internally over the source elements provided, in contrast to Collections where explicit iteration is required.

Generating Streams

With Java 8, Collection interface has two methods to generate a Stream

  • stream()  Returns a sequential stream considering collection as its source.
  • parallelStream()  Returns a parallel Stream considering collection as its source.

List<String> strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,””, “jkl”);
List<String> filtered = strings.
stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

forEach

Stream has provided a new method forEach to iterate each element of the stream. The following code segment shows how to print 10 random numbers using forEach.

Random random = new Random();
random.ints().limit(10).
forEach(System.out::println);

map

The map method is used to map each element to its corresponding result. The following code segment prints unique squares of numbers using map.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

filter

The filter method is used to eliminate elements based on a criteria. The following code segment prints a count of empty strings using filter.

List<String>strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,””, “jkl”);
//get count of empty string
int count = strings.stream().filter(string -> string.isEmpty()).count();

limit

The limit method is used to reduce the size of the stream. The following code segment shows how to print 10 random numbers using limit.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

sorted

The sorted method is used to sort the stream. The following code segment shows how to print 10 random numbers in a sorted order.

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Parallel Processing

parallelStream is the alternative of stream for parallel processing. Take a look at the following code segment that prints a count of empty strings using parallelStream.

List<String> strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,””, “jkl”);
//get count of empty string
int count = strings.
parallelStream().filter(string -> string.isEmpty()).count();

It is very easy to switch between sequential and parallel streams.

Collectors

Collectors are used to combine the result of processing on the elements of a stream. Collectors can be used to return a list or a string.

List<String>strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,””, “jkl”);
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

System.out.println(“Filtered List: ” + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(“, “));
System.out.println(“Merged String: ” + mergedString);

Statistics

With Java 8, statistics collectors are introduced to calculate all statistics when stream processing is being done.

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);

IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();

System.out.println(“Highest number in List : ” + stats.getMax());
System.out.println(“Lowest number in List : ” + stats.getMin());
System.out.println(“Sum of all numbers : ” + stats.getSum());
System.out.println(“Average of all numbers : ” + stats.getAverage());

      1. Predicate

The word predicate is often used in mathematics to mean something function-like that takes a value for an argument and returns true or false.

 

      1. (int x) -> x + 1

to mean “the function that, when called with argument x, returns the value x + 1.”

      1. Sequential processing:

import static java.util.stream.Collectors.toList;
List<Apple> heavyApples =
inventory.stream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());

      1. Parallel processing:

import static java.util.stream.Collectors.toList;
List<Apple> heavyApples =
inventory.parallelStream().filter((Apple a) -> a.getWeight() > 150)
.collect(toList());

 

Leave a comment