# Java 8 Notes

Java, originally evolved from the Oak language, was born in early 1996 with its major version as Java 1 or JDK 1.0. Java was initially designed and developed by James Gosling at Sun Microsystems. Java 8 or JDK 8.0 is one of the major releases of the Java programming language in 2014.

This article would walk you through new features were added in Java 8:

**- Lambda Expressions: ** a new language feature allowing us to treat actions as objects.

**- Method References: ** enable us to define Lambda Expressions by referring to methods directly using their names.

**- Optional:** special wrapper class used for expressing optionally

**- Functional Interface:** an interface with maximum one abstract method; implementation can be provided using a Lambda Expression

**- Default methods:** give us the ability to add full implementations in interfaces besides abstract methods

**- Stream API: ** a special iterator class that allows us to process collections of objects in a functional manner


### 1. Lambda Expression
       
        parameter -> expression
 
        (param_1, param_2) -> expression
         
        (param_1, param_2) -> {code block}

VD: 


```
import java.util.ArrayList;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = new ArrayList<>();
    numbers.add(5);
    numbers.add(9);
    numbers.add(8);
    numbers.add(1);
    numbers.forEach( (n) -> System.out.println(n));
  }
}
``` 

### 2. Method References

- reference a method, reduce the verbosity of some lambdas.

- using double colons:

- there are two reference types:

  
   Refer to static method

```
List<String> messages = Arrays.asList("hello", "phamduyhieu.com", "readers!")

// lambda:
messages.forEach(word -> StringUtils.capitalize(word));

// method reference
messages.forEach(StringUtils::capitalize);

``` 

   Refer to instance method


```
public class BicycleComparator implements Comparator<Bicycle> {

    @Override
    public int compare(Bicycle o1, Bicycle o2) {
        return o1.getFrameSize().compareTo(o2.getFrameSize());
    }
}

ArrayList<Bicycle> myList = new ArrayList<>();
myList.add(new Bicycle("hieu", 20));
myList.add(new Bicycle("hieu", 30));
myList.add(new Bicycle("hieu", 40));
myList.add(new Bicycle("hieu", 10));

BicycleComparator myComparator = new BicycleComparator();

// lambda
List<Bicycle> newList = myList.stream().
                sorted((a, b) -> myComparator.compare(a, b)).collect(Collectors.toList());

// with method reference
List<Bicycle> newList2 = myList.stream().sorted(myComparator::compare).collect(Collectors.toList());

``` 

#### 3. Optional

- was created to avoid any runtime **NullPointerExceptions**, eliminate many *null* checks. Also, we can develop clean and neat APIs.


```
// before Optional

if (name != null) {
    System.out.println(name.length());
}

// with Optional
// deal with nullable values explicitly with a shorter way

opt.ifPresent(n -> System.out.println(n.length()));

// orElse() is used to return the wrapped value if it is present, and its argument otherwise

String nullName = null;
String nameTest = Optional.ofNullable(nullName).orElse("Hieu");
System.out.println(nameTest);

``` 

#### 4. Functional Interfaces

- is an interface with one single abstract method, no more, no less
- support the lambda expression in java 8

- Before java 8, we would usually create a class for every case where we needed to encapsulate a single piece of functionality => a lot of unnecessary boilerplate code.


```
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("my runnable");
    }
});
``` 
If you look at the above code, the actual part that is of use is the code inside **run()** method. Rest all of the code is because of the way java programs are structured.

- Java 8 Functional interfaces and Lambda Expressions help us in writing smaller and cleaner code by removing a lot of boilerplate code.


```
Thread thread2 = new Thread(() -> System.out.println("my runnable"));
``` 

#### 5. Default Method

- is a method with an implementation which can be found in an interface.

- to add a new functionality to an interface, while maintaining backward compatibility with classes that are already implementing the interface:


```
public interface Vehicle {
    public void move();
    default void hoot() {
        System.out.println("peep!");
    }
}
``` 
- For example, the **Collection** interface can have a default implementation of the **forEach** method without requiring the classes implementing this interface to implement the same.

#### 6. Streams

- represents a sequence of objects from a source such as a collection, which supports aggregate operations. 

```
int sum = Arrays.stream(new int[]{1, 2, 3, 4, 5})
        .filter(i -> i >= 3)
        .map(i -> i * 3)
        .sum();
``` 
- in simple terms, a stream is an iterator whose role is to accept a set of actions to apply on each of the elements it contains.

- Difference between Map and flatMap:

     Both **map** and **flatMap** are intermediate stream operations that receive a function and apply this function to all the elements of a stream. But the difference is that for the **map**, this function returns a **value**, but for **flatMap**, this function returns a **stream**.



















