Java 8 features
Published: 2024-07-14 14:34:40

## Java 8 New Features:

1. Lambda Expression
2. Stream API
3. Default and static methods in Interfaces
4. Functional interfaces
5. Optional class
6. New Date and Time API
7. Functional Programming & Why Functional Programming?
8. Method reference, Constructor reference

## Collections:

Collection => Main interface
List, Set, Map, Queue => Child interfaces of Collection interface.

## List => ArrayList, LinkedList, Vector, Stack.

We can have duplicate elements.
Insertion order is maintained.
It allows null values.
Duplicate elements are differentiated by means of index.

## ArrayList:

Internal data structure => Growable array.
Use case => Search Operations => ArrayList implements RandomAccess interface
Worst case => Insertion / Deletion in the middle positions. => Shift operations are costly.

## LinkedList:

Internal data structure => Doubly linked list.
Use case => Insertion / Deletion in the middle positions.
Worst case => Search Operations => Sequential search.


## Set => HashSet, LinkedHashSet, TreeSet

Does not allow duplicates.
Insertion order is not maintained (except for LinkedHashSet).
One null value is allowed.

## HashSet:

The underlying data structure is hashtable.

## LinkedHashSet:

Underlying data structure hashtable + LinkedList
Insertion order is maintained.

## TreeSet:
Elements are sorted (Natural sorting order(Ascending) or customized sorting order)

```java
TreeSet<Employee> employees = new TreeSet<>(); // Employee objects are comparable.
// Employee objects are comparable, which means the Employee class should implement a Comparable interface.

package java.lang;

public interface Comparable<T> {
public int compareTo(T t);
}

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private double salary;

    // setXxx() and getXxx()

    public int compareTo(Employee e2) {
        // Employee e1 = this;   // We can directly use "this".
        // Comparison logic.
    }

}
```

If a class is not implementing the Comparable interface, we will get an exception``ClassCastException``.

### Ascending:

if
``
e1 < e2 return -ve
e1 > e2 return +ve
e1 == e2 return 0
``

### Descending:

``
If e1 < e2 retrun +ve
e1 > e2 return -ve
e1 == e2 return 0
``

## Comparator<T> interface:

```java
package java.util;

public interface Comparator<T> {

    public int compare(T t1, T t2);

}
```

Q. Advantages of Comparator interface over Comparable?
Comparators can be used to sort the class based on more than one property of the class because we don't implement the Comparator interface directly in the class, we create another class that implements the Comparator interface and then we specify which property we want to use to sort the main class on

```java
class EmployeeNameComparator implements Comparator<Employee> {

    public int compare(Employee e1, Employee e2) {
        // Logic of comparison
    }

}

TreeSet<Employee> employees = new TreeSet<>(new EmployeeNameCompartor());
```
## Map:
Collection of key-value pair (Entry).
Keys are unique, values can be duplicated.

Map => HashMap, LinkedHashMap, TreeMap, Hashtable, Properties


Q. When we deal with Set or Map collections, it is recommended to override equals() and hashcode() methods, why so?
This is because there is a contract between ``equals()`` and ``hashcode()`` method which states that if two objects are equals, their hashcode should also be the same, but two objects don't need to be equal even if their hashcode is the same.
Hence it is necessary to override ``hashcode()`` if we are overriding ``equals()``


## Functional Interfaces:

The interface contains only one abstract method. They may have default and static methods.
Java 8 has introduced a new annotation ``@FunctionalInterface``

Java 8 has also introduced a new package => ``java.util.function``

This package contains 44 functional interfaces. These functional interfaces are used in Stream API.
Example: 

```java
public interface Calculator {
public int calculate(int x, int y);
}
```

### 1st Way

```java
public class CalculatorImpl implements Calculator {

    @Override
    public int calculate(int x, int y) {
        return x + y;
    }

}
```
### 2nd Way => Anonymous Inner class.

```java
Calculator c = new Calculator() {
   @Override
   public int calculate(int x, int y) {
      return x + y;
   }  
}
```
## Lambda Expression:

```java
Calculator c = (x,y)->return x+y;
```
A lambda expression is a concise representation of an anonymous function that can be passed around, it does not have a name, it has a list of parameters, a body, a return type, and possibly a list of exceptions that can be thrown.

Anonymous => It's anonymous because it has no explicit name.

Function => We say function because lambda isn't associated with a particular class like a method is. But like a method, a lambda expression has a list of parameters, return type, and a list of exceptions that can be thrown.

Passed around => A lambda expression can be passed as an argument to a method or stored in a variable.

Concise => You don't need to write a boilerplate code like we do for anonymous classes.


## Functions in in Java

``java.util.function`` package interfaces are categorized into 4:

1. Predicate
2. Consumer
3. Supplier
4. Function

```java
public interface Consumer<T> {  
 public void accept(T t);
}

public interface Predicate<T> {
public boolean test(T t);
}

public interface Supplier<T> {
public T get();
}

public interface Function<T, R> {
public R apply(T t);
}

```

## Stream API

Collection or Array => Main purpose => To store the data.

```java
Set<Transaction>
Set<Employee>
```

```sql
Find all employees of HR department having salary > 30000.

SELECT * FROM employees
WHERE department='HR' AND salary > 30000
```

Declarative way => What you want.
Imperative way =>

 Streams let you manipulate collections of data in a declarative way (you express a query rather than code and ad-hoc implementation for it).

1. A stream does not hold any data. It pulls the data it processes from the source (collection/Array/File).
2. A stream does not modify the data it processes.
3. The source may be unbound
   -- It is not finite.
   -- But most of the time, it only means that the size of the source is not known at build time.
4. One Thread => One Task
   Second Thread => Second Task
   Most of the computers have multiple cores (dual, quad, octa-core)
   Parallel streams => It uses multiple cores of your computer.

Q. What is Stream?
=> From a technical point of view: Stream is a typed interface.

```java
public interface Stream<T> extends BaseStream<T, Stream<T>> {

}
```

### We also have IntStream, LongStream, and DoubleStream.

Q. How to build Streams?

From collection object

```java
   List<Dish> menu = new ArrayList<>();
   Stream<Dish> stream = menu.stream();
```
Empty stream

```java
   Stream stream = Stream.empty();
```
``of()`` method that accepts a single parameter.

```java
   Stream<String> stream = Stream.of("Anna");
```
``of()`` method that accepts multiple parameters.

```java
   Stream<String> stream = Stream.of("Anna", "Alex", "Bob", "Peter");
```

A stream on the lines of text files.

```java
   Stream<String> stream = Files.lines(path);
```
Create a stream from an array.

```java
int arr[] = { 10, 20, 30, 40, 10, 20, 60, 80, 90, 30};
IntStream stream = Arrays.stream(arr);
stream.distinct()
.forEach(n -> System.out.println(n));

```

Create a stream with infinite data.

## Optional<T> class: Added in Java 8.

Available in ``java.util`` package.

It is used to avoid null reference checks.

Creating Optional Object:

Empty Optional

```java
Optional<Car> car = Optional.empty();
```
Optional From non-null values

```java
Optional<Car> car = Optional.of(car);
```
// If the Car object is null, NullPointerException will be thrown immediately once you try to access the properties of the Car.

Optional from null.

```java
Optional<Car> car = Optional.ofNullable(car);
```
// If the Car object is null, then it will return empty Optional.

## Method Reference:

There are 3 different kinds of method references:

1. A method reference to a static method.

```java

interface S {
	void say();
}
class M{
	public static void say(){
		System.out.println("this is static method say()");
	}
	public static void main(String a[]){
		S s = M:: say;
		s.say();
	}
}
```

Output:

```
this is static method say()
```
Examples are: 

```java
   Integer::parseInt  
   StringUtils::capitalize
```

Usage: 

```
   List<String> names = Arrays.asList("Anna", "Peter", "Alex", "George");

   // names.forEach(name -> StringUtils.capitalize(name));

   names.forEach(StringUtils::capitalize);
```

2) A method reference to an instance method of an arbitrary object.

```java

interface S {
	void say();
}
class M{
	public  void say(){
		System.out.println("this is instance method say()");
	}
	public static void main(String a[]){
		M m = new M();
		S s = m:: say;
		s.say();
	}
}
```
Output:

```
this is instance method say()
```

For eg. ``Dish::isVegeterian``
``String::length``
A method reference to an instance method of an existing object.
For eg. ``System.out::println``

3. Constructor reference

```java
interface S {
	void say();
}
class M{
	public  M (){
		System.out.println("this is constructor reference method say()");
	}
	public static void main(String a[]){
		
		S s = M :: new;
		s.say();
	}
}
```
Output:

```
this is the constructor reference method say()
```