> For the complete documentation index, see [llms.txt](https://amartyushov.gitbook.io/tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://amartyushov.gitbook.io/tech/programming-languages/java/features-track/java-8.md).

# Java 8

## Lambda expressions

\[optional] With explicit data types:

```java
String[] names = directory.list((File dir, String name) -> name.endsWith(".java"));
```

Block syntax

```
String[] names = directory.list((File dir, String name) -> {
    return name.endsWith(".java")
});
```

## Method references

Advantage over lambda:

* shorter
* includes the names of the class containing the method => easier to read

### Syntax

* **`object::instanceMethod`** (e.g. `System.out::println`, equivalent `x -> System.out.println(x)`)
* **`Class::staticMethod`** (e.g. `Math::max`, equivalent `(x,y) -> Math.max(x,y)`)
* **`Class::instanceMethod`** invoke a method on a reference to an object supplied by the context (e.g. `String::length`, equivalent `x -> x.length()`)

## Constructor reference

```
public class Person {
    private String name;
    
    public Person(){}
 
    public Person (String name) {
        this.name = name;
    }   
    // other methods
}    
```

```
List<Person> people = names.stream().map(Person::new).collect(Collectors.toList());
```

Based on the context in lambda expression => constructor with String arg is used.

### Copy constructor

```
public Person (Person p) {
    this.name = p.name;
}
```

:bulb: Useful if you want to isolate original instances.

```
Person before = new Person("Before");
List<Person> people = Stream.of(before).collect(Collectors.toList());
Person after = people.get(0);

assertTrue(before == after);                 

before.setName("changed");
assertEquals("changed", after.getName());    
```

Using copy constructor it is possible to break  that connection.

```
people = Stream.of(before).map(Person::new).collect(Collectors.toList());
Person after = people.get(0);

assertFalse(before == after);
assertEquals(before, after);

before.setName("changed");
assertFalse(before.equals(after));
```

### To Array

```
People[] people = names.stream()
    .map(Person::new)            // constructor reference for Person
    .toArray(Person[]::new);     // constructor reference for array of Person       
```

## Functional interfaces

```
@java.lang.FunctionalInterface        // provides compile-time check
public interface TheChecker {
    boolean check(String s);    // no need for abstract keyword
    // int anotherMethod();     // if added => not a functional interface any more
    
    default String sayHello() {
        return "Hello";
    }
    
    static void theStaticMethod() {
        System.out.println("I'm a static method in an interface");
    }
}

usage
TheChecker checker = new ConcreteChecker();
checker.sayHello();
```

all methods are `public` => no need to specify deliberately

```
// not a functional, because it has 2 abstract methods in total
public interface TheChild extends TheChecker {
    int bla();
}
```

Methods from `Object` don't count against the single abstract method limit (e.g. `Comparator` is still functional interface).

### java.util.function

#### Consumer

```
void accept(T t)

default Consumer<T> andThen(Consumer<? super T> after)
```

How `andThen` method works:

```
v--- 1. c.accept("Java2s.com");        
c.andThen(c).andThen(c).accept("Java2s.com");
          ^          ^      
          |          |           
          |  3.  c.accept("Java2s.com");               
          |
2. c.accept("Java2s.com");  
```

| Interface      | single abstract method |
| -------------- | ---------------------- |
| IntConsumer    | void accept(int x)     |
| DoubleConsumer | void accept(double x)  |
| LongConsumer   | void accept(long x)    |
| BiConsumer     | void accept(T t, U u)  |

#### Supplier

```
T get()
```

| Interface       | Single abstract method |
| --------------- | ---------------------- |
| IntSupplier     | int getAsInt()         |
| DoubleSupplier  | double getAsDouble()   |
| LongSupplier    | long getAsLong()       |
| BooleanSupplier | boolean getAsBoolean() |

Use case:

* concept of `deferred` execution

```java
public static void info(Logger logger, Supplier<String> message) {
  if (logger.isLoggable(Level.INFO))
      logger.info(message.get());
}
```

#### Predicate

```java
boolean test(T t)
```

:bulb: You can have a method which has a parameter of Predicate type.

:bulb: Can be a good idea to have frequently used predicates as a constants.

:bulb: It is possible to combine predicates using default methods:

```java
car.filter(cars, PREDICATE_IS_RED.or(PREDICATE_IS_FAST));

public List<Car> filter(List<Car> cars, Predicate<Car> pre);
```

#### Function

```java
[Function<T,R>] R apply(T t)
```

`Transforms input parameter of type T to output of type R`&#x20;

`If (T == R) => UnaryOperator;`

#### BiFunction

```java
[BiFunction<T,U,R>] R apply(T t, U u)
```

`if (R == T == U) => BinaryOperator` (e.g. Math.max)

## Stream

`Stream is a sequence of elements that does not save elements or modify the original source`&#x20;

`Streams do not process any data until a terminal expression is reached`&#x20;

{% code fullWidth="true" %}

```java
long count = stream
  .map((value) -> { return value.toUpperCase(); }) // just listener is added. Non-terminal operation
  .map((value) -> { return value.substring(0,3); }) // just listener is added. Non-terminal operation
  .count(); // Terminal operation. Triggers stream processing.
```

{% endcode %}

Terminal operations: anyMatch(), allMatch(), noneMatch(), count(), collect(), findAny(), forEach(),...

### Create streams

```java
class Stream {
    
    @SafeVarargs
    public static<T> Stream<T> of(T... valuse) {
        return Arrays.stream(values);
    }
    
    // returns infinite sequential ordered stream
    static <T> Stream<T> iterate(T seed, UnaryOperator<T> f){}
    
    // produces sequential unordered stream by invoking Supplier
    static <T> Stream<T> generate(Supplier<T> s)
}
```

```java
List<BigDecimal> nums =
    Stream.iterate(BigDecimal.ONE, n -> n.add(BigDecimal.ONE) )
        .limit(10)
        .collect(Collectors.toList());
System.out.println(nums);
// prints [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Stream.generate(Math::random) 
    .limit(10)
    .forEach(System.out::println)
```

#### IntStream, LongStream, DoubleStream

```java
static IntStream range(int startInclusive, int endExclusive)
static IntStream rangeClosed(int startInclusive, int endInclusive)
static LongStream range(long startInclusive, long endExclusive) 
static LongStream rangeClosed(long startInclusive, long endInclusive)
```

```java
List<Integer> ints = IntStream.range(10, 15)
    .boxed() // without boxed() DOES NOT COMPILE
    .collect(Collectors.toList());
```

### Boxed streams

```java
List<Integer> ints = IntStream.of(3, 1, 4, 1, 5, 9)
    .boxed() // to convert int to Integer for collection
    .collect(Collectors.toList());
```

```java
List<Integer> ints = IntStream.of(3, 1, 4, 1, 5, 9)
    .mapToObj(Integer::valueOf)
    .collect(Collectors.toList())
```

### Reduction operations

```java
long count = Arrays.stream(strings)
        .map(String::length)
        .count();
        
int totalLength = Arrays.stream(strings) 
        .mapToInt(String::length)
        .sum();        
        
OptionalDouble ave = Arrays.stream(strings)
        .mapToInt(String::length)
        .average();
        
OptionalInt max = Arrays.stream(strings)
        .mapToInt(String::length)
        .max();                        
```

`Reduce method:`&#x20;

```java
OptionalInt reduce(IntBinaryOperator op)
int reduce(int identity, IntBinaryOperator op)

int sum = IntStream.rangeClosed(1, 10) 
    .reduce((x, y) -> x + y)
    .orElse(0);
// x - accumulator, y - value of the element in stream

int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
    .reduce(0, Integer::sum);
    
Stream.of("this", "is", "a", "list")
        .reduce("", String::concat); // thisisalist
        
Stream.of("this", "is", "a", "list")
        .collect(Collectors.joining());                
```

#### Most general form of reduce

```java
<U> U reduce(U identity,
    BiFunction<U,? super T,U> accumulator,
    BinaryOperator<U> combiner)
```

Consider a Book class, the goal is to create a Map\<Integer, Book> from List\<Book>

```java
public class Book { 
    private Integer id; 
    private String title;
}

books.stream()
    .reduce(new HashMap<Integer,Book>(),     // collect to
            (map, book) -> {        // how to add one element
                map.put(book.getId(), book);
                return map:
            },    
            (map1, map2) -> {       // how to compibe two maps. Needed for multithreading     
                map1.putAll(map2);
                return map1;
            });    
```

### Debugging streams with peak

```java
Stream<T> peek(Consumer<? super T> action)
```

`returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as they are consumed from the resulting stream.`&#x20;

## Converting Strings to stream

```java
String implements CharSequence, it means

public default IntStream chars() {...}
public default IntStream codePoints() {...}
```
