java 8

LAMBDA





replace  anonymous implementations
of single method interfaces

Lambda


 new Thread(new Runnable() {
     @Override
     public void run() {
         compute();
     }
 }).start();

() -> { ... }

 new Thread(() -> compute()).start();

Lambda


 Set<T> bucket = new HashSet<>();
 Applications.each(anIterator, new Action<>() {
     @Override
     public void perform(T value) {
         bucket.add(value);
     }
 });

 value -> { ... }

 Set<T> bucket = new HashSet<>();
 Applications.each(anIterator, value -> bucket.add(value));

LAMBDA


 Applications.map(strings, new Delegate<Ipv4, String>() {
     @Override
     public Ipv4 perform(String dottedIpAddress) {
         return Ipv4.parse(dottedIpAddress);
     }
 });

value -> { return ... }

 Applications.map(strings, dottedIpAddress -> Ipv4.parse(dottedIpAddress));

Method reference





method as function object
implementing a single method interface

Method reference


 Applications.map(anIterator, new Delegate<Ipv4, String>() {
     @Override
     public Ipv4 perform(String dottedIpAddress) {
         return Ipv4.parse(dottedIpAddress);
     }
 });

static Ipv4 parse(String dottedIpAddress)

 Applications.map(anIterator, Ipv4::parse);

Method reference


 Applications.each(anIterator, new Action<T>() {
     @Override
     public void perform(T value) {
         System.out.println(value);
     }
 });

void println(Object value) { ... }

 Applications.each(anIterator, System.out::println);

Method reference


 Collections.sort(ipv4List, new Comparator<Ipv4>() {
     @Override
     public int compare(Ipv4 former, Ipv4 latter) {
         return former.compareTo(latter);
     }
 });

int compareTo(Ipv4 other)

static int compareTo(Ipv4 this, Ipv4 other)

 Collections.sort(ipv4List, Ipv4::compareTo);

Default methods



provide a default implementation
of an interface method


adding default methods
does not break implementing classes

Default Methods


 public interface Iterator<E> {

     boolean hasNext();

     E next();

     void remove();
 }

 public abstract class ReadOnlyIterator<E> implements Iterator<E> {

     @Override
     public void remove() {
         throw new UnsupportedOperationException("read-only iterator");
     }
}

Default methods


 public interface Iterator<E> {

     boolean hasNext();

     E next();

     default void remove() {
         throw new UnsupportedOperationException("remove");
     }

     default void forEachRemaining(Consumer<E> action) {
         while(hasNext() {
             action.accept(next());
         }
     }
 }

Enhanced collections





i.e. a bunch of default methods

Enhanced collections



 Iterator.remove() throws UnsupportedOperationException

 Iterator.forEachRemaining(E -> void)

 Iterable.forEach(E -> void)

Enhanced collections



 Collection.removeIf(E -> boolean)

 Collection.stream()

 List.replaceAll(E -> E)

 List.sort((E, E) -> int)

Enhanced collections


 Map.forEach((K, V) -> void)
Map as a cache
 Map.compute(K, (K, V) -> V)

 Map.computeIfAbsent(K, K -> V)

 Map.computeIfPresent(K, (K, V) -> V)

 Map.getOrDefault(K, V)

 Map.merge(K, V, (V, V) -> V)

 Map.putIfAbsent(K, V)

 Map.replace(K, V)

 Map.replaceAll((K, V) -> V)

Streams



lazy

sequential - parallel

finite - infinite

consumable

Streams


CONSTRUCTION


 collection.stream()

 Stream.of(T... values)

 Arrays.stream(T[] array, int startInclusive, int endExclusive) 

Streams


INTERMEDIATE OPERATIONS

 .map(T -> R)

 [0,1,2,3].map(i -> i+1) => [1,2,3,4]

 .flatMap(T -> Stream<R>)

 [0,1,2,3].flatMap(i -> IntStream.range(0,i)) => [ 0 , 0,1 , 0,1,2]

 .filter(T -> boolean)

 [3,6,2,5,1].filter(i -> i < 3) => [2,1]

STREAMS


INTERMEDIATE OPERATIONS

 .distinct()

 [1,4,2,5,2,3,1,2].distinct() => [1,4,2,5,3]

 .limit(long maxSize)

 [0,1,2,3,...].limit(5) => [0,1,2,3,4]

 .skip(long n)

 [0,1,2,3,...].skip(5) => [5,6,7,8,...]

STREAMS


INTERMEDIATE OPERATIONS

 .sorted()

 [3,1,5,3,8,3].sorted() => [1,3,3,3,5,8]

 .peek(T -> { ... })

 triggers a side effect when an element passes through

Streams


COLLECTING



 .collect(Collector)

Streams


COLLECTING

 Collectors.toList()

 Stream.of(1,2,3).collect(Collectors.toList()) => List[1,2,3]

 Collectors.toCollection(Provider<Collection>)

 Stream.of(1,2,1,2).collect(Collectors.toCollection(HashSet::new))

 => Set[1,2]

STREAMS


COLLECTING

 Collectors.toMap(T -> K, T -> V)

 Stream.of("192.168.1.10", "192.168.3.101", "127.0.0.1")
         .collect(Collectors.toMap(
                 ip -> Ipv4.parse(ip).mask("255.255.255.0"),
                 Function.identity()
         )
 );

 => Map {
     "192.168.1.0": "192.168.1.10",
     "192.168.3.0": "192.168.3.101",
     "127.0.0.0"  : "127.0.0.1"
    }

Streams


COLLECTING

 Collectors.groupingBy(T -> K)

 Stream.of("192.168.1.10", "192.168.1.37", "192.168.3.101", "127.0.0.1")
         .collect(Collectors.groupingBy(
                 ip -> Ipv4.parse(ip).mask("255.255.255.0")
         )
 );

 => Map {
     "192.168.1.0": List["192.168.1.10","192.168.1.37"],
     "192.168.3.0": List["192.168.3.101"],
     "127.0.0.0"  : List["127.0.0.1"]
    }

Streams


COLLECTING

 Collectors.joining(delimiter)

 Collectors.joining(delimiter, prefix, suffix)

 Streams.of("a", "b", "c").collect(Collectors.joining(",", "[", "]"));

 => "[a, b, c]"

Streams


TERMINAL OPERATIONS

 .allMatch(T -> boolean)
 .anyMatch(T -> boolean)
 .noneMatch(T -> boolean)

 Stream.of("asante", "sana", "cocco", "banana")
         .anyMatch(word -> word.length() >= 6)

 => true

Streams


TERMINAL OPERATIONS

 .findAny()    // explicitly nondeterministic

 .findFirst()

 .count()

 Stream.of(1,2,3).count() => 3

 .forEach(T -> void)

 // performs a side effect on all the elements of the stream

STREAMS


TERMINAL OPERATIONS


 .reduce(T identity, (T, T) -> T accumulator)

 Stream.of(1,2,3,4).reduce(1, (a, b) -> a * b) => 24

Streams


TERMINAL OPERATIONS

/!\ BEWARE OF INFINITE STREAMS /!\
 

Optional


container for a possibly missing value

(maybe / option in other languages)

 Optional.of("value")

 Optional.empty()

 Optional.ofNullable(somethingNullish)

Optional


perform mappings, filtering and actions
with the contained value, if present

 .map(T -> R)

 .flatMap(T -> Optional<R>)

 .filter(T -> boolean)

 .ifPresent(T -> { ... })

Optional


get a default value or throw

 .orElse(T)

 .orElseGet(() -> T)

 .orElseThrow(() -> Throwable)

if an other optional is needed as default value

 Optional<T> optional = Optional.empty();
 Optional<Optional<T>> duplicate = optional.map(Optional::of);
 Optional<T> result = duplicate.orElse(defaultOptional);

Noteworthy



parallel array operations

primitive types iterators and streams
(int, long, double)

nashorn javascript engine

java.time
Made with Slides.com