Java 8 Features at a Glance

Naveen AnamaneniUpdated · 5 min read

Ask any experienced Java developer which release changed their daily work the most, and most will say Java 8. Released in March 2014, it let Java code describe what to do with data instead of spelling out every loop, and it finally replaced the old, confusing date classes. It was also a long-term support release, so many companies ran it for years, and interview questions about it are still everywhere. This lesson is a one-page reference: every Java 8 feature, where it is taught in depth, and a short tour. For a full walkthrough with more examples, see "Java 8 Features" in the Functional Programming chapter.

What Did Java 8 Add?

Java 8 is the Java release, and a long-term support (LTS) release, that added lambda expressions, functional interfaces, method references, the Stream API, Optional, default and static interface methods and the java.time date and time API.

Language Features

FeatureWhat it gives youRead more
Lambda expressionsShort anonymous functions: n -> n * 2"Lambda Expressions in Java"
Functional interfacesInterfaces with one abstract method, the target type of a lambda: Predicate, Function, Supplier, Consumer"Functional Interfaces in Java"
Method referencesString::length, System.out::println"Method References in Java"
Default and static methods in interfacesInterfaces can carry method bodies, so they can grow without breaking implementations"Default, Static and Private Methods in Interfaces"
Effectively finalLambdas and inner classes can use local variables that are never reassigned, without writing final"Effectively Final Variables and Lambda Capture"
Repeatable and type annotationsThe same annotation more than once; annotations on any use of a type"Meta-Annotations in Java"

Library and JVM Features

FeatureWhat it gives youRead more
Stream APIfilter, map, reduce, collect pipelines over collections"Stream API in Java"
OptionalA return type that says "there may be no value""Optional Class in Java"
java.timeImmutable, clear date and time classes: LocalDate, LocalDateTime, Duration"LocalDate, LocalTime and LocalDateTime"
CompletableFutureChain asynchronous tasks without blocking"CompletableFuture in Java"
forEach, removeIf, Map.merge, computeIfAbsentCollection methods that take lambdas"Built-In Functional Interfaces in Java"
String.join, StringJoinerJoin strings with a separator"Modern String Methods in Java"
Base64Standard Base64 encoding and decoding
Metaspace replaces PermGenClass metadata lives in native memory and grows as needed"JVM: The Java Virtual Machine"

A Java 8 Tour

Let's see a small program that uses the headline features together.

Lambda8.java▶ Try it
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
 
public class Lambda8 {
    interface Greeter {
        String name();
 
        default String greet() {                          // default method
            return "Hello, " + name();
        }
    }
 
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Navika", "Srihitha", "Advitha");
        List<Integer> marks = Arrays.asList(91, 84, 77);
 
        names.forEach(n -> System.out.print(n + " "));    // lambda
        System.out.println();
 
        int total = marks.stream()                        // stream
                .filter(m -> m >= 80)
                .mapToInt(Integer::intValue)              // method reference
                .sum();
        System.out.println("total of marks >= 80: " + total);
 
        Map<Integer, List<String>> byLength = names.stream()
                .collect(Collectors.groupingBy(String::length));
        System.out.println("names by length: " + byLength);
 
        Optional<String> longName = names.stream()
                .filter(n -> n.length() > 10)
                .findFirst();
        System.out.println(longName.orElse("no name longer than 10"));
 
        LocalDate exam = LocalDate.of(2026, Month.MARCH, 2); // java.time
        LocalDate start = LocalDate.of(2026, Month.JANUARY, 5);
        System.out.println("days to prepare: "
                + ChronoUnit.DAYS.between(start, exam));
 
        Greeter g = () -> "Advitha";                // functional interface
        System.out.println(g.greet());
    }
}
Output
Navika Srihitha Advitha
total of marks >= 80: 175
names by length: {6=[Navika], 7=[Advitha], 8=[Srihitha]}
no name longer than 10
days to prepare: 56
Hello, Advitha

Explanation:

  1. forEach with a lambda replaces a for loop that only prints.
  2. The stream pipeline filters, converts with a method reference, and sums, without a single loop variable.
  3. groupingBy builds a map from name length to names in one line.
  4. Optional makes "nothing found" explicit, and orElse gives the fallback.
  5. LocalDate and ChronoUnit.DAYS.between do date arithmetic correctly, with months starting at 1 (unlike the old Calendar, where January was 0).
  6. Greeter has one abstract method, so a lambda can implement it, and it inherits the default method greet.

Practice

  1. Easy: Rewrite this loop as a stream: int count = 0; for (int m : marks) if (m < 80) count++;
  2. Harder: Using java.time, print the day of the week of 15 August 2026 and the number of days from today until then.

Quick check: Java 8

4 questions
1Which feature lets an interface have a method body?
2What is a functional interface?
3Which package holds the Java 8 date and time API?
4Was Java 8 an LTS release?

Key Takeaways

Was this tutorial helpful?

Lesson 561 of 578