java 8 - nuts and bold - sfeir benelux
TRANSCRIPT
Comparator<Person> comparator = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.firstname.compareTo(o2.firstname);
}
};
Comparator<Person> comparator1 =
(o1, o2) -> throw new Exception("Something went wrong");
THE CONTENT OF THE LAMBDA MUST MATCH THE SIGNATURE OF THE METHOD IMPLEMENTED
Comparator<Person> comparator1 =
(o1, o2) -> throw new RuntimeException("Something went wrong");
RUNTIME EXCEPTION - THIS WILL COMPILE
@FunctionalInterface
public interface Compare<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
public interface Postfixable {
public final static int UNARY_MESSAGE_PRIORITY = 1;
public final static int BINARY_MESSAGE_PRIORITY = 2;
// ...
int getPriority();
public default boolean le(Postfixable other) {
return this.getPriority() <= other.getPriority();
}
}
public interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(positive(a));
}
}
Formula formula = (a) -> sqrt( a * 100);
public interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(positive(a));
}
}
Formula formula = (a) -> sqrt( a * 100);
DOES NOT COMPILE
public static interface MyInterface1 {
default void foo(){
System.out.println("hello");
}
}
public static interface MyInterface2 {
default void foo(){
System.out.println("bye");
}
}
public static abstract class MyClass
implements MyInterface1, MyInterface2 {
public abstract foo();
}
UN-IMPLEMENTING THE DEFAULT METHOD SOLVES THE PROBLEM
public static class MyClass implements MyInterface1, MyInterface2 {
public void foo() {
MyInterface1.super.foo();
MyInterface2.super.foo();
}
}
public static class MyClass1 implements MyInterface1 {
public void foo(){
System.out.println("bonjour");
}
}
public static class MyClass2 extends MyClass1 implements MyInterface2 {
}
public static class MyClass1 implements MyInterface1 {
public void foo(){
System.out.println("bonjour");
}
}
public static class MyClass2 extends MyClass1 implements MyInterface2 {
}
IN CASE OF AMBIGUITY A CLASS TAKES PRECEDENCE
public class Car {
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}
public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}
public void repair() {
System.out.println("Repaired " + this.toString());
}
public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}
}
final Car car = Car.create(Car::new);
final List<Car> cars = Arrays.asList(car);
cars.forEach(Car::collide);
final Car car = Car.create(Car::new);
final List<Car> cars = Arrays.asList(car);
cars.forEach(Car::repair);
final Car car = Car.create(Car::new);
final List<Car> cars = Arrays.asList(car);
final Car police = Car.create(Car::new);
cars.forEach(police::follow);
public static UtfToCodePoint findUtfToCodePoint(final Charset charset) {
switch (charset) {
case UTF8:
case UTF8BOM:
return Converter::utf8ToCodePoint;
case UTF16BE:
return Converter::utf16beToCodePoint;
case UTF16LE:
return Converter::utf16leToCodePoint;
case UTF32BE:
return Converter::utf32beToCodePoint;
case UTF32LE:
return Converter::utf32leToCodePoint;
default:
throw new UnicodeException("Unknown charset!");
}
}
public class Person {
final private String firstName;
final private String lastName;
public Person() {}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
public interface PersonFactory {
Person create(String firstName, String lastName);
}
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate<String> nonNull = Objects::nonNull;
Predicate<String> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("123"); // "123"
Consumer<Person> greeter = p -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));
Optional<String> optional = Optional.of("foo");
optional.isPresent(); // true
optional.get(); // "foo"
optional.orElse("fallback"); // "foo"
optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "f"
Optional<String> fullName = Optional.ofNullable(null);
System.out.println("Full Name is set? " + fullName.isPresent());
// Full Name is set? false
System.out.println("Full Name: " + fullName.orElseGet(() -> "[none]"));
// Full Name: [none]
System.out.println(fullName.map(s -> "Hey " + s + "!").orElse("Hey Stranger!"));
// Hey Stranger!
Optional<String> firstName = Optional.of("Tom");
System.out.println("First Name is set? " + firstName.isPresent());
// Full Name is set? true
System.out.println("First Name: " + firstName.orElseGet(() -> "[none]"));
// Full Name: Tom
System.out.println(firstName.map(s -> "Hey " + s + "!").orElse("Hey Stranger!"));
// Hey Tom!
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i,src.get(i));
}
}
List<A> as = new ArrayList<>();
List<B> bs = new ArrayList<>();
List<C> cs = new ArrayList<>();
Collections.copy(List<A>, List<B>);
Collections.copy(List<A>, List<A>);
Collections.copy(List<A>, List<C>);
Collections.copy(List<B>, List<B>);
Collections.copy(List<B>, List<A>); // KO
Collections.copy(List<B>, List<C>);
Collections.copy(List<C>, List<B>); // KO
Collections.copy(List<C>, List<A>); // KO
Collections.copy(List<C>, List<C>);
public class A {
}
public class B extends A {
}
public class C extends B {
}
void forEach(Consumer<? super T> action)
List<Double> temperature = Arrays.asList(20.0, 22.0, 22.5);
temperature.forEach(System.out::println);
void sort(Comparator<? super E> c)
List<Double> temperature = Arrays.asList(20.0, 22.0, 22.5);
temperature.sort((a, b) -> a > b ? -1 : 1);
boolean removeIf(Predicate<? super E> filter)
List<Double> temperature = Arrays.asList(20.0, 22.0, 22.5);
temperature.removeIf(s -> s > 22);
void replaceAll(UnaryOperator<E> operator)
List<Double> temperature = Arrays.asList(20.0, 22.0, 22.5);
temperature.replaceAll(s -> Math.pow(s, 0.5));
void forEach(BiConsumer<? super K, ? super V> action)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.forEach((a, b) -> System.out.println(a + " wrote " + b + " books"));
V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.compute("Clive Cussler", (a, b) -> b + 1);
// If the compute function returns null then the entry for that key is removed
// from the map. If the key is not present then a new entry is added.
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.computeIfAbsent("Agatha Christie", b -> b.length());
// The entry is added only if the computed value is not null.
V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.computeIfPresent("Tom Clancy", (a, b) -> b + 1);
// Note that this function also removes an element if the new value computed from
// the passed lambda expression is null.
V getOrDefault(Object key, V defaultValue)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.getOrDefault("AuthorA", 0)
V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
authorBooks.merge("AuthorB", 1, (a, b) -> a + b);
System.out.println(authorBooks.get("AuthorB")); // 1
authorBooks.merge("AuthorB", 1, (a, b) -> a + b);
System.out.println(authorBooks.get("AuthorB")); // 2
V putIfAbsent(K key, V value)
Map<String , Integer> authorBooks = new HashMap<String , Integer>();
authorBooks.put("Robert Ludlum", 27);
authorBooks.put("Clive Cussler", 50);
authorBooks.put("Tom Clancy", 17);
System.out.println(authorBooks.putIfAbsent("AuthorC", 2)); // null
System.out.println(authorBooks.putIfAbsent("AuthorC", 2)); // 2
boolean remove(Object key, Object value)
V replace(K key, V newValue)
boolean replace(K key, V oldValue, V newValue)
void replaceAll (BiFunction<? super K, ? super V, ? extends V> function)
Comparator<Person> comparator = (p1, p2) -> {
int r = p1.lastname.compareTo(p2.lastname);
if (r != 0)
return r;
return p1.firstname.compareTo(p2.firstname);
};
Comparator<Person> comparator4 = Comparator
.comparing(Person::getLastname)
.thenComparing(Person::getFirstname);
Comparator<Person> comparator = Comparator
.comparing(Person::getLastname)
.reverse()
.thenComparing(Person::getFirstname);
// The result won't be always the same
Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
stream.parallel().map(e -> {
if (seen.add(e)) return 0; else return e;
}
);
// with a stateless lambda expression the results would
always be the same.
IntStream.range(0,5).parallel().map(x -> x * 2).toArray()
// use reduction instead of mutable accumulators
http://gotocon.com/dl/goto-amsterdam-2014/slides/PaulSandoz_PerchanceToStreamWithJava8.pdf
Source Decomposibility Characteristics
ArrayList (and arrays) Excellent SIZED, ORDERED
LinkedList Poor SIZED, ORDERED
HashSet Good SIZED, DISTINCT
TreeSet Good SIZED, DISTINCT, SORTED, ORDERED
IntStream.range() Excellent SIZED, DISTINCT, SORTED, ORDERED
Stream.iterate() Poor ORDERED
BufferedReader.lines() Poor ORDERED
SplittableRandom.ints() Excellent
String<String> stream = Arrays.asList("a", "b", "c").stream();
String<String> stream = Stream.of("a", "b", "c")
Stream<String> stream = Files.lines(Paths.get(uri));
String<String> stream = Arrays.asList("a", "b", "c").stream();
String<String> stream = Stream.of("a", "b", "c")
Stream<String> stream = Files.lines(Paths.get(uri));
collection.stream();
collection.parellelStream();
static <T> Stream<T> generate(Supplier<T> s)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> concat(Stream<? extends T> a,
Stream<? extends T> b)
static <T> Stream<T> of(T... values)
static <T> Stream<T> empty()
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)
IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)
LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper)
<R> Stream<R> map(Function<? super T,? extends R> mapper)
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)
IntStream mapToInt(ToIntFunction<? super T> mapper)
LongStream mapToLong(ToLongFunction<? super T> mapper)
long count()
boolean allMatch(Predicate<? super T> predicate)
boolean anyMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)
Optional<T> findAny()
Optional<T> findFirst()
Optional<T> max(Comparator<? super T> comparator)
Optional<T> min(Comparator<? super T> comparator)
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
<R,A> R collect(Collector<? super T,A,R> collector)
<R> R collect(Supplier<R> supplier,
BiConsumer<R,? super T> accumulator,
BiConsumer<R,R> combiner)
public void closure() {
List<Supplier<Integer>> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
list.add(() -> i);
}
}
public void closure() {
List<Supplier<Integer>> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
list.add(() -> i);
}
}
DOES NOT COMPILEThe value of « i » changes along the way
public void closure() {
List<Supplier<Integer>> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
final int j = i;
list.add(() -> j);
}
list.forEach((e) -> System.out.print(e.get())); // 12345
}
COMPILEA new « j » variable is created at each iteration
public void closure() {
List<Supplier<Integer>> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
final int j = i;
list.add(() -> j);
}
list.forEach((e) -> System.out.print(e.get())); // 12345
}
The « final » keyword is not mandatory as the value of « j » is set once and for allIn this example « j » IS EFFECTIVELY FINAL
public void closure() {
List<Supplier<Integer>> list =
IntStream.range(1, 6)
.mapToObj((i) -> (Supplier<Integer>) () -> i)
.collect(Collectors.toList());
list.forEach((e) -> System.out.print(e.get())); // 12345
}
public class Closure {
private int index = 1;
public void closure() {
List<Supplier<Integer>> list =
IntStream.range(-5, 0)
.mapToObj((i) -> (Supplier<Integer>) () -> index++)
.collect(Collectors.toList());
list.forEach((e) -> System.out.print(e.get())); // 12345
}
}
http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.htmlhttp://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html