1. Lambda expressions

Lamba expressions may be familiar to those who have used other streaming programming languages, and a Lambda expression (or function) is simply an anonymous function, that is, a function that has no name and no bound identifier. They are written exactly where they are needed, often as arguments to other functions.

The basic syntax for a lambda expression:

(parameters) -> expression or (parameters) -> {statements; } or () -> expression

A typical example of a lambda expression is shown below

(x, y) -> x + y  

Rules for writing lambda expressions

  1. A lambda expression can have zero, one, or more arguments
  2. The type of the parameter can be declared either explicitly or inferred from the context
  3. Multiple arguments are enclosed in mandatory parentheses and separated by commas; empty parentheses are used to indicate a set of empty arguments
  4. When there is a single argument, parentheses are not enforced if the type is inferred,
  5. Lambda expressions can have zero, one, or more bodies
  6. If the subject of a lambda expression has a single statement, then curly braces are not required, and the return type of the anonymous function is the same as that of the body expression. When there are multiple execution statements in the body, these statements must be enclosed in curly braces

2 Functioninterface

The more functional interfaces become single abstract method interfaces, they allow only one abstract method to be used inside of them. Java8 introduced an annotation @FunctionInterface, which will report an error at compile time if you annotate an interface that violates the functional interface rules.

The instance

@FunctionalInterface
public interface MyFirstFunctionalInterface {
    public void firstWork();
}

Note that the @FunctionalInterface annotation is also valid if omitted. It is only used to inform the compiler to enforce a single abstract method within the interface. Since the default method is not abstract, feel free to add the default method to your FunctionalInterface.

Another important point to keep in mind is that if an interface declares an abstract method that overrides one of the public methods,java.lang.Object, this will not count toward the abstract method count either, because any implementation of the interface will have an implementation from java.lang.Object or somewhere else. For example, here is a fully valid functional interface.

@FunctionalInterface public interface MyFirstFunctionalInterface { public void firstWork(); @Override public String toString(); Override public Boolean equals(Object obj); Override public Boolean equals(Object obj); // Override the method in Object without counting}

3. Default methods

Java8 allows you to add non-abstract methods to interfaces, but these methods must be declared as default methods. Default methods, introduced in Java8, enable lambda expressions with default methods

example

public interface Moveable {
    default void move(){
        System.out.println("I am moving");
    }

The Moveable interface defines a method move and provides a default implementation. If any class implements the interface, it can be called without having to implement the move method version of the interface

For example,

public class Animal implements Moveable{
    public static void main(String[] args){
        Animal tiger = new Animal();
        tiger.move();
    }
}
  
Output: I am moving

Of course, if you want to customize your own Move method, you can provide your own custom implementation and override the method.

4. Java8 flow

Stream is the biggest change in Java 8. It provides a way to Stream data, including filtering, transformation, or anything else that might be useful to an application. The Stream API in Java 8 supports different types of iterations

List<String> items; String prefix; List<String> filteredList = items.stream().filter(e ->(! e.startsWith(prefix))).collect(Collectors.toList());

Here, items.stream is the data that we want items to use to process the collection using the Stream API

5. Date/time API changes

The Date person of type DATE is obsolete. You can use LOCALDATE, LOCALTIME, and LOCALDATETIME

  • thisLocalDateClass represents a date. No representation of time or time zone.
  • theLocalTimeThe level represents time. No date or time zone representation.
  • thisLocalDateTimeClass represents a date-time. There is no representation of time zones

Lambda provides three additional classes like the one above, OffsetDate,OffsetTime, and OffsetDateTime, if you want to use both time and time zones. For time zones, you can use “+8” or “Europe/Paris”.

LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 20);
LocalDateTime localDateTime = LocalDateTime.now(); 
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
Time stamp and duration

To represent a specific timestamp at any point in time, you need to use Instant. The Instant class represents precise moments of time in nanoseconds. Operations on Instant include comparing Instant with another and adding or subtracting a duration.

Instant instant = Instant.now(); Instant instant1 = instant.plus(Duration.ofMillis(5000)); Instant instant2 = instant.minus(Duration.ofMillis(5000)); Instant instant3 = instant.minusSeconds(10);

Duration is a concept of permission, first introduced in Java 8, that represents the time difference between two timestamps.

Duration duration = Duration.ofMillis(5000); duration = Duration.ofSeconds(60); duration = Duration.ofMinutes(10);

Duration deals with small amounts of time, such as milliseconds, seconds, minutes, and time. If you want a longer Duration, you need to use the Period class

Period period = Period.ofDays(6); period = Period.ofMonths(6); period = Period.between(LocalDate.now(), LocalDate.now().plusDays(60));