Java 8 Features at a Glance
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
| Feature | What it gives you | Read more |
|---|---|---|
| Lambda expressions | Short anonymous functions: n -> n * 2 | "Lambda Expressions in Java" |
| Functional interfaces | Interfaces with one abstract method, the target type of a lambda: Predicate, Function, Supplier, Consumer | "Functional Interfaces in Java" |
| Method references | String::length, System.out::println | "Method References in Java" |
| Default and static methods in interfaces | Interfaces can carry method bodies, so they can grow without breaking implementations | "Default, Static and Private Methods in Interfaces" |
| Effectively final | Lambdas and inner classes can use local variables that are never reassigned, without writing final | "Effectively Final Variables and Lambda Capture" |
| Repeatable and type annotations | The same annotation more than once; annotations on any use of a type | "Meta-Annotations in Java" |
Library and JVM Features
| Feature | What it gives you | Read more |
|---|---|---|
| Stream API | filter, map, reduce, collect pipelines over collections | "Stream API in Java" |
Optional | A return type that says "there may be no value" | "Optional Class in Java" |
java.time | Immutable, clear date and time classes: LocalDate, LocalDateTime, Duration | "LocalDate, LocalTime and LocalDateTime" |
CompletableFuture | Chain asynchronous tasks without blocking | "CompletableFuture in Java" |
forEach, removeIf, Map.merge, computeIfAbsent | Collection methods that take lambdas | "Built-In Functional Interfaces in Java" |
String.join, StringJoiner | Join strings with a separator | "Modern String Methods in Java" |
Base64 | Standard Base64 encoding and decoding | |
| Metaspace replaces PermGen | Class 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.
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());
}
}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, AdvithaExplanation:
forEachwith a lambda replaces a for loop that only prints.- The stream pipeline filters, converts with a method reference, and sums, without a single loop variable.
groupingBybuilds a map from name length to names in one line.Optionalmakes "nothing found" explicit, andorElsegives the fallback.LocalDateandChronoUnit.DAYS.betweendo date arithmetic correctly, with months starting at 1 (unlike the oldCalendar, where January was 0).Greeterhas one abstract method, so a lambda can implement it, and it inherits the default methodgreet.
Practice
- Easy: Rewrite this loop as a stream:
int count = 0; for (int m : marks) if (m < 80) count++; - Harder: Using
java.time, print the day of the week of 15 August 2026 and the number of days from today until then.
Key Takeaways
Was this tutorial helpful?