Java 8 Features

Java 8 is one of the most important releases in Java history. It introduced functional programming, stream processing, lambda expressions, and major API enhancements.

1. Lambda Expressions

What is the use of Lambda Expressions?

👉 To write cleaner, shorter, more readable code

👉 Makes Collections Processing Easy

Lambda expressions are used to write cleaner, shorter, and more readable code.

They allow passing behavior as a parameter and enable functional programming using the Stream API.

Lambdas reduce boilerplate, simplify multithreading, and work with functional interfaces like Predicate, Function, and Consumer. Default and static methods do not affect this rule.

We cannot use lambda expressions on normal interfaces that have multiple abstract methods.

Syntax:

(parameters) -> expression

(parameters) -> { statements }

What is the use of a Functional Interface?

2. Functional Interface

A Functional Interface is an interface with exactly has one abstract method.

To support lambda expressions: Lambda requires exactly one abstract method, so it can map the lambda to that method.

Functional interfaces allow lambdas, enable functional programming, reduce boilerplate, and allow behavior to be passed around in code.

Example:

@FunctionalInterface

interface MyInterface {

    void test();

}

--

Examples:

Runnable

Callable

Comparator

Predicate

Function

Consumer

Supplier

What is the use of Default Methods?

A default method is a method with a body inside an interface.

Why are default methods introduced?

✔ 1. To avoid breaking existing implementations

Before Java 8: Adding a new method in interface → breaks ALL implementing classes

After Java 8:

✔ New method can be added as default

✔ Existing classes don't break

✔ To provide common functionality: Interfaces can now provide reusable code 

What is the use of Static Methods in Interface?

Static methods inside interfaces belong only to the interface, not implementing classes.

Example:

interface Vehicle {

    default void start() {

        System.out.println("Starting...");

    }

    static void stop() {

        System.out.println("Stopping...");

    }

}


3. Method Reference

What is the use of Method Reference?

Method references are used to make lambda expressions more concise and readable.

They reuse existing methods instead of writing logic again in a lambda.

We can apply method references in four cases:

1. Static methods - Class::staticMethod,

2. Instance methods of an object - Class::instanceMethod,

3. Instance methods of any object of a class - object::instanceMethod,

4. Constructors - Class::new.

4. Stream API

What is a Stream in Java?

A Stream is pipeline-based data processing on a sequence of elements, and used to perform functional-style programming. 

It allows to filter, transform, aggregate, and collect data without modifying the underlying source.

Key Characteristics:

👉Not a data structure — it doesn’t store elements

👉Immutable — operations do not change source data

👉Lazy evaluation — intermediate operations execute only when a terminal operation runs

👉Internal iteration — Java controls looping, not the developer

👉Functional — uses lambdas, method references

👉Composable — supports pipeline chaining

👉Single-use — once consumed, cannot be reused

Stream Pipeline Structure:

source → intermediate operations → terminal operation

Types of Stream Operations:

Intermediate (lazy, return Stream):

filter()

map()

sorted()

distinct()

limit()

peek()

Terminal (trigger execution):

collect()

forEach()

reduce()

count()

findFirst()

Example:

Find top 3 highest salaries using Stream

List<Integer> top3 = salaries.stream()

                             .sorted(Comparator.reverseOrder())

                             .limit(3)

                             .collect(Collectors.toList());


What is parallelStream()?

parallelStream() processes elements concurrently using multiple threads

internally backed by ForkJoinPool.commonPool().

Example:

List<String> names = List.of("A", "B", "C", "D");

names.parallelStream()

     .forEach(System.out::println);

How Parallel Stream Works Internally:

✔ Uses ForkJoin Framework

✔ Splits the data into sub-tasks via Spliterator

✔ Each task runs on a different worker thread

✔ Results merged using reduce/combine





5. Optional 

What is Optional in Java?

Optional is used to avoid null pointer exceptions and write safer, cleaner code.

It represents a value that may or may not exist.

Optional provides methods like of(), ofNullable(), isPresent(), ifPresent(), orElse(), orElseGet(), orElseThrow(), map(), flatMap(), and filter() to handle missing values without explicit null checks.

Example:

Optional<String> name = Optional.ofNullable(null);

name.orElse("default");     // returns "default"

name.orElseThrow(() -> new RuntimeException("Value missing"));

6. Date & Time API (java.time)

Core Conceptual Difference between util.Date and java.time

Aspect

java.util.Date

Java 8 Date/Time (`java.time.*`)

Package

java.util

java.time

Design

Old, flawed

Modern, well-designed 

Mutability

 ✅ Mutable

 ❌ Immutable 

Thread Safety

 ❌ Not thread-safe  

 ✅ Thread-safe

Time representation

Milliseconds since Epoch

Diverse, explicit date/time models

Time Zone handling

Implicit, confusing

Explicit, clear

Formatting/Parsing

`SimpleDateFormat` (not thread-safe)

`DateTimeFormatter` (thread-safe)

API style

Procedural

Fluent, functional

Range & precision

Milliseconds

Nanoseconds

Domain accuracy

Weak

Strong domain separation

 Mutability:

        Date date = new Date(); // Sun Nov 23 13:22:39 IST 2025

        date.setTime(0); // modifies original object

        System.out.println(date); // given - Thu Jan 01 05:30:00 IST 1970


        LocalDate localDate = LocalDate.now(); // 2025-11-23

        localDate.plusDays(1); // returns new object

        System.out.println(localDate); // same result - 2025-11-23

        LocalDate update = localDate.plusDays(1); // return new object - 2025-11-23

        

Timezone Confusion:

java.util.Date always prints in system timezone


Java 8 separates concepts clearly:

LocalDate → only date

LocalTime → only time

LocalDateTime → date & time, no timezone

ZonedDateTime → date & time WITH timezone

Instant → UTC timestamp

Precision:

java.util.Date - gives till milliseconds

Instant, LocalDateTime - gives nanoseconds

Thread Safety:

Date, Calendar, SimpleDateFormat - Mutable

java.time classes are immutable

Calendar Exists Because Date Is Broken:

util.Date API did NOT support:

> adding days, months, years

> subtracting dates

> getting month, year, day

> localization

> timezone conversions

To over come this we use util.Calendar

        Calendar cal = Calendar.getInstance();

        cal.add(Calendar.DAY_OF_MONTH, 5);

Issue with Calendar: it consider months from 0-11


In java.time

LocalDate localDate = LocalDate.now();

localDate.plusDays(1);


Period, Duration Calculation:

java.util.Date and java.util.Calendar do NOT have dedicated time-span types.

Before Java 8, developers had to compute differences manually

In java8

Duration: Represents time-based amount

LocalTime start = LocalTime.of(10, 30);

LocalTime end = LocalTime.of(13, 10);

Duration duration = Duration.between(start, end);

Period: Represents date-based amount

LocalDate join = LocalDate.of(2020, 1, 15);

LocalDate today = LocalDate.of(2025, 11, 22);

Period period = Period.between(join, today);




No comments:

Post a Comment