# 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() {...}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://amartyushov.gitbook.io/tech/programming-languages/java/features-track/java-8.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
