https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html
https://medium.com/@akashshinde/why-you-should-start-using-java-8-d818375f4f59
http://zeroturnaround.com/rebellabs/java-8-best-practices-cheat-sheet/
https://zeroturnaround.com/rebellabs/java-8-streams-cheat-sheet/
https://www.ibm.com/developerworks/library/j-java8idioms2/index.html
https://www.voxxed.com/blog/2016/05/gang-four-patterns-functional-light-part-4/
https://www.infoq.com/presentations/java8-lambda-streams
https://dzone.com/articles/concurrenthashmap-in-java8
http://www.deadcoderising.com/
https://dzone.com/articles/rulebook-a-simple-rules-engine-that-leverages-java
https://github.com/java8/Java8InAction
https://habrahabr.ru/post/216431/
http://minborgsjavapot.blogspot.com/2016/11/work-with-parallel-database-streams.html
http://alexsderkach.io/comparing-java-8-rxjava-reactor/
hats.removeIf(IHat::hasEarFlaps);
https://www.airpair.com/java/posts/parallel-processing-of-io-based-data-with-java-streams
There are numerous interfaces in the Java library that declare a single abstract method; few such interfaces include:
// 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); }
Java 8 has introduced the concept of “functional interfaces” that formalizes this idea. A functional interface specifies only one abstract method.
interfaces do not inherit from Object, but rather implicitly declare many of the same methods as Object
These can be represented using Lambda expressions, Method reference and constructor ref
Annotation @FunctionalInterface can be used for compiler level errors
http://stackoverflow.com/questions/43661433/java-default-interface-methods-concrete-use-cases
A functional interface is any interface that contains only one abstract method. (A functional interface may contain one or more default methods or static methods.) Because a functional interface contains only one abstract method, you can omit the name of that method when you implement it. To do this, instead of using an anonymous class expression, you use a lambda expression
interface CheckPerson { boolean test(Person p); }
you can use the Predicate<T> interface in place of CheckPerson. This interface contains the method boolean test(T t):
interface Predicate<T> { boolean test(T t); }
printPersons( roster, (Person p) -> p.getGender() == Person.Sex.MAL && p.getAge() >= 18 );
public static void printPersonsWithPredicate( List<Person> roster, Predicate<Person> tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); <-- this is hardcoded action, how to pass arbitrary action here? } } }
Answer: user Consumer - a functional interface that contains an abstract method that can take one argument of type Person and returns void. The Consumer<T> interface contains the method void accept(T t), which has these characteristics. The following method replaces the invocation p.printPerson() with an instance of Consumer<Person> that invokes the method accept:
public static void processPersons( List<Person> roster, Predicate<Person> tester, Consumer<Person> block) { for (Person p : roster) { if (tester.test(p)) { block.accept(p); } } }
What if you want to do more with your members' profiles than printing them out. Suppose that you want to validate the members' profiles or retrieve their contact information? In this case, you need a functional interface that contains an abstract method that returns a value. The Function<T,R> interface contains the method R apply(T t). The following method retrieves the data specified by the parameter mapper, and then performs an action on it specified by the parameter block:
public static void processPersonsWithFunction( List<Person> roster, Predicate<Person> tester, Function<Person, String> mapper, Consumer<String> block) { for (Person p : roster) { if (tester.test(p)) { String data = mapper.apply(p); block.accept(data); } } }
The following method retrieves the email address from each member contained in roster who is eligible for Selective Service and then prints it:
processPersonsWithFunction( roster, p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25, p -> p.getEmailAddress(), email -> System.out.println(email) );
Generalization
public static <X, Y> void processElements( Iterable<X> source, Predicate<X> tester, Function <X, Y> mapper, Consumer<Y> block) { for (X p : source) { if (tester.test(p)) { Y data = mapper.apply(p); block.accept(data); } } }
Interfaces - do not have instance variables
static methods inside interfaces
default method
An important use for default methods is interface evolution. Consider for example the
Collection interface that has been a part of Java for many years. Suppose that way
back when, you provided a class
Later, in Java 8, a stream method was added to the interface.
Suppose the stream method was not a default method. Then the Bag class no longer
compiles since it doesn’t implement the new method. Adding a nondefault method to an
interface is not source-compatible.
Lambda
You can supply a lambda expression whenever an object of an interface with a single
abstract method is expected. Such an interface is called a functional interface.
http://www.oreilly.com/programming/free/introducing-java-8.csp
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
http://www.infoq.com/presentations/java8-examples
http://shekhargulati.com/7-days-with-java-8/
https://www.youtube.com/watch?v=rtAredKhyac
Comparator
https://praveer09.github.io/technology/2016/06/21/writing-comparators-the-java8-way/
Chaining comparators
myList.sort(comparing(Apple::getWeight)
.reserved()
.thenComparing(Apple::getCountry)
);
Predicate interface
The idea of using predicates is simply to replace the hard-coded condition inside the if clause by a call to a predicate, which then becomes a parameter. This means you can write only one method, taking a predicate as a parameter, and you can still cover all your use-cases, and even already support use-cases you do not know yet:
Each particular predicate can be defined as a standalone class, if used at several places, or as an anonymous class:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
final Customer customer = new Customer("BruceWaineCorp");
final Predicate<PurchaseOrder> condition = new Predicate<PurchaseOrder>() {
public boolean apply(PurchaseOrder order) {
return order.getCustomer().equals(customer);
}
};
public List<PurchaseOrder> listOrders(Predicate<PurchaseOrder> condition){
final List<PurchaseOrder> selection = new ArrayList<PurchaseOrder>();
for (PurchaseOrder order : orders) {
if (condition.apply(order)) {
selection.add(order);
}
}
return selection;
}
java.util.function.Predicate source–
package java.util.function;
import java.util.Objects;
@FunctionalInterface public interface Predicate<T> {
boolean test(T t);
negate()
and()
or()
}
Predicate<Apple> notRed = redApple.negate() -- negate of existing predicate
Predicate<Apple> RedandHeavy = redApple and (a->a.getWeight()>10) or (...)
Accumulator Adder
http://liviutudor.com/2014/06/26/java-8-accumulators-and-adders/
Completable Future
http://codingjunkie.net/completable-futures-part1/
https://habrahabr.ru/post/213319/
Stream and parallelStream
https://habrahabr.ru/company/luxoft/blog/270383/
Return 5 names of dishes with low calories sorted by # of calories
menu.stream()
.filter( d-> d.getCalories() <400 )
.sorted(comparing (Dish::getCalories))
.map(Dish::getName)
.distinct()
.limit (5)
.collect(toList()); <-- terminal operation
menu.stream()
.forEach(System.out.println); <-- terminal operation
menu.stream()
.count() ; <-- terminal operation
Group by:
Map<Dish.type, List<Dish>> groupByType =
menu.stream()
.collect(groupingBy (Dish::getType));
flatMap(Arrays::stream) -- flattened into single stream
Termilal Operations
allMatch
anyMatch
noneMatch
findFirst
findAny
Optional<T>
bool isPresent()
void ifPresent<Consumer<T> block)
T get()
T orElse(T other) - returns values if present of default
Reduce
int sum=numbers.stream().reduce(0, (a,b)->a+b);
int sum=numbers.stream().reduce(Integer::sum); <- same as above using method's reference
int max=numbers.stream().reduce(Integer::max);
public Article getFirstJavaArticle() { for (Article article: articles) { if (article.getTags().contains("Java")) { return article; } } return null; }
Решим задачу, используя Stream API.
public Optional<Article> getFirstJavaArticle() { return articles.stream() .filter(article -> article.getTags().contains("Java")) .findFirst(); }