Type inference is a feature of Java which provides ability to compiler to look at each method invocation and corresponding declaration to determine the type of arguments.
Java provides improved version of type inference in Java 8.
Here, we are creating arraylist by mentioning integer type explicitly at both side. The following approach is used earlier versions of Java.

List<Integer> list = new ArrayList<Integer>();  

In the following declaration, we are mentioning type of arraylist at one side. This approach was introduce in Java 7. Here, you can left second side as blank diamond and compiler will infer type of it by type of reference variable.

List<Integer> list2 = new ArrayList<>();   

Improved Type Inference
In Java 8, you can call specialized method without explicitly mentioning of type of arguments.

showList(new ArrayList<>());  

Example
You can use type inference with generic classes and methods.

import java.util.ArrayList;
import java.util.List;
public class TypeInferenceExample {
 public static void showList(List < Integer > list) {
  if (!list.isEmpty()) {
   list.forEach(System.out::println);
  } else System.out.println("list is empty");
 }

 public static void main(String[] args) {

  // An old approach(prior to Java 7) to create a list  
  List < Integer > list1 = new ArrayList < Integer > ();
  list1.add(11);
  showList(list1);

  // Java 7    
  List < Integer > list2 = new ArrayList < > (); // You can left it blank, compiler can infer type  
  list2.add(12);
  showList(list2);

  // Compiler infers type of ArrayList, in Java 8  
  showList(new ArrayList < > ());
 }
}

Output

11
12
list is empty

Type inference for Custom Classes

class GenericClass <X> {
 X name;
 public void setName(X name) {
  this.name = name;
 }
 public X getName() {
  return name;
 }
 public String genericMethod(GenericClass < String > x) {
  x.setName("John");
  returnx.name;
 }
}

public class TypeInferenceExample {
 public static void main(String[] args) {
  GenericClass < String > genericClass = new GenericClass < String > ();
  genericClass.setName("Peter");
  System.out.println(genericClass.getName());

  GenericClass < String > genericClass2 = new GenericClass < > ();
  genericClass2.setName("peter");
  System.out.println(genericClass2.getName());

  // New improved type inference  
  System.out.println(genericClass2.genericMethod(new GenericClass < > ()));
 }
}

Output

Peter
peter
John

Lambdas implement a functional interface.Anonymous Inner Classes can extend a class or implement an interface with any number of methods.
Variables – Lambdas can only access final or effectively final.
State – Anonymous inner classes can use instance variables and thus can have state, lambdas cannot.
Scope – Lambdas can’t define a variable with the same name as a variable in enclosing scope.
Compilation – Anonymous compiles to a class, while lambda is an invokedynamic instruction.

Syntax
Lambda expressions looks neat as compared to Anonymous Inner Class (AIC)

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("in run");
        }
    };

    Thread t = new Thread(r);
    t.start(); 
}

//syntax of lambda expression 
public static void main(String[] args) {
    Runnable r = ()->{System.out.println("in run");};
    Thread t = new Thread(r);
    t.start();
}

Scope
An anonymous inner class is a class, which means that it has scope for variable defined inside the inner class.

Whereas,lambda expression is not a scope of its own, but is part of the enclosing scope.

Similar rule applies for super and this keyword when using inside anonymous inner class and lambda expression. In case of anonymous inner class this keyword refers to local scope and super keyword refers to the anonymous class’s super class. While in case of lambda expression this keyword refers to the object of the enclosing type and super will refer to the enclosing class’s super class.

//AIC
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int cnt = 5;    
                System.out.println("in run" + cnt);
            }
        };

        Thread t = new Thread(r);
        t.start();
    }

//Lambda
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = ()->{
            int cnt = 5; //compilation error
            System.out.println("in run"+cnt);};
        Thread t = new Thread(r);
        t.start();
    }

Performance
At runtime anonymous inner classes require class loading, memory allocation, and object initialization and invocation of a non-static method while lambda expression is a compile-time activity and don’t incur extra cost during runtime. So the performance of lambda expression is better as compare to anonymous inner classes.

  1. Optional is a wrapper class which makes a field optional which means it may or may not have values.
  2. ptional as a single-value container that either contains a value or doesn’t (it is then said to be “empty”)
  3. The advantage compared to null references is that the Optional class forces you to think about the case when the value is not present. As a consequence, you can prevent unintended null pointer exceptions.
  4. The intention of the Optional class is not to replace every single null reference. Instead, its purpose is to help design more-comprehensible APIs so that by just reading the signature of a method, you can tell whether you can expect an optional value. This forces you to actively unwrap an Optional to deal with the absence of a value.

Lets take the below code

String version = computer.getSoundcard().getUSB().getVersion();

In the above piece of java code if any of the 3 values other the Version is NULL will throw a null pointer exception. To prevent this lets add a null check

String version = "UNKNOWN";
if(computer != null){
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null){
    USB usb = soundcard.getUSB();
    if(usb != null){
      version = usb.getVersion();
    }
  }
}

Now the above code has become Clumsy with less readability and lot of boilerplate code has been added.
In languages like Groovy these conditions could be handles like one below

String version = computer?.getSoundcard()?.getUSB()?.getVersion();
(or)
String version = 
    computer?.getSoundcard()?.getUSB()?.getVersion() ?: "UNKNOWN";

Now lets replace the above code with new Optional in Java 8

public class Computer {
  private Optional<Soundcard> soundcard;  
  public Optional<Soundcard> getSoundcard() { ... }
  ...
}

public class Soundcard {
  private Optional<USB> usb;
  public Optional<USB> getUSB() { ... }

}

public class USB{
  public String getVersion(){ ... }
}

The advantage compared to null references is that the Optional class forces you to think about the case when the value is not present. As a consequence, you can prevent unintended null pointer exceptions.

What is the Point of Optional when the same could be done using NULL Check?
If you are doing NULL check the traditional way there would be no much difference. However, the difference is felt when you are carrying out chaining operations in streams and the datatypes returned are optional.The difference may not be significant in this case but as the chain of objects increases e.g. person.getAddress.getCity().getStreet().getBlock(),

Methods in Optional
get()
If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException

void ifPresent(Consumer consumer)
If a value is present, it invokes the specified consumer with the value, otherwise does nothing.

boolean isPresent()
Returns true if there is a value present, otherwise false.

static Optional ofNullable(T value)
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.

T orElse(T other)
Returns the value if present, otherwise returns other.

T orElseGet(Supplier other)
Returns the value if present, otherwise invokes other and returns the result of that invocation.

orElseThrow(Supplier exceptionSupplier)
Returns the contained value, if present, otherwise throws an exception to be created by the provided supplier.

Lets take a simple example where Optional returns Empty or Value based on some Condition

package com.example.demo;
import java.util.Optional;
public class Test {

 public static void main(String[] args) {
  //IfPresent
  Optional < String > strOpt = getName(" Piggy");
  System.out.print("First Call -");
  strOpt.ifPresent(System.out::println);


  Optional < String > strOpt2 = getName("");
  System.out.print("Second Call -");
  strOpt2.ifPresent(System.out::println);

  System.out.println();

  //IsPresent and get
  Optional < String > strOpt3 = getNewName(" Biggy");
  System.out.print("Third Call -");

  if (strOpt3.isPresent())
   System.out.println(strOpt3.get());


  //orElse
  Optional < String > strOpt4 = getNewName(null);
  System.out.print("Fourth Call -");
  System.out.println(strOpt4.orElse(" Hippi"));


 }

 public static Optional < String > getName(String strName) {
  if (strName.length() > 0)
   return Optional.of(strName);
  else
   return Optional.empty();
 }

 public static Optional < String > getNewName(String strName) {
  //Optional strNewName = (strName!=null)?Optional.of(strName):Optional.empty();
  return Optional.ofNullable(strName);
 }
}

Output

First Call - Piggy
Second Call -
Third Call - Biggy
Fourth Call - Hippi