Java 8 introduced several major features that improved the language’s efficiency, readability, and performance. Below are the key features:
1. Lambda Expressions (Functional Programming)
Lambda expressions provide a concise way to express anonymous functions.
✅ Example:
// Without Lambda (before Java 8)
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
};
// With Lambda (Java 8)
Comparator<Integer> comparatorLambda = (a, b) -> a.compareTo(b);
2. Functional Interfaces & Default Methods in Interfaces
Java 8 introduced the @FunctionalInterface annotation and allowed default methods in interfaces.
✅ Example:
@FunctionalInterface
interface MyFunction {
void sayHello();
// Default method (optional)
default void print() {
System.out.println("Default method in Interface");
}
}
public class Main {
public static void main(String[] args) {
MyFunction func = () -> System.out.println("Hello, Lambda!");
func.sayHello();
func.print();
}
}
3. Stream API (Processing Collections)
Streams allow functional-style operations on collections without modifying the original data.
✅ Example:
import java.util.Arrays;
import java.util.List;
public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Puneet", "Aayush", "Sahil", "Prakash");
// Filter names starting with 'P' and print them
names.stream()
.filter(name -> name.startsWith("P"))
.forEach(System.out::println);
}
}
✅ Benefits:
- Supports filtering, mapping, sorting in a single pipeline.
- Lazy evaluation improves performance.
4. Optional Class (Avoid NullPointerException)
Optional<T> is used to handle null values safely and avoid NullPointerException.
✅ Example:
import java.util.Optional;
public class OptionalExample {
public static void main(String[] args) {
Optional<String> name = Optional.ofNullable(null);
// If present, print it; otherwise, print default
System.out.println(name.orElse("Default Name"));
}
}
✅ Benefits:
- Eliminates null checks.
- Provides methods like
isPresent(),orElse(),orElseThrow().
5. New Date & Time API (java.time package)
Java 8 introduced a better, immutable date-time API to replace java.util.Date and Calendar.
✅ Example:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public class DateTimeExample {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("Date: " + date);
System.out.println("Time: " + time);
System.out.println("Date & Time: " + dateTime);
}
}
✅ Benefits:
- Thread-safe & immutable.
- More readable and supports time zones.
6. Method References (Shorter Lambda Expressions)
Method references (::) allow reusing existing methods inside lambdas.
✅ Example:
import java.util.Arrays;
import java.util.List;
public class MethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Puneet", "Aayush", "Sahil", "Prakash");
// Using Lambda
names.forEach(name -> System.out.println(name));
// Using Method Reference
names.forEach(System.out::println);
}
}
7. Collectors (Grouping & Joining in Streams)
Collectors help group, join, and summarize data from streams.
✅ Example:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CollectorsExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Puneet", "Aayush", "Sahil", "Puneet");
// Collect distinct names as a comma-separated string
String result = names.stream()
.distinct()
.collect(Collectors.joining(", "));
System.out.println(result); // Output: Puneet, Aayush, Sahil
}
}
8. New forEach() Method in Collections
Java 8 introduced the forEach() method for iterating collections.
✅ Example:
import java.util.Arrays;
import java.util.List;
public class ForEachExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
}
}
9. Base64 Encoding & Decoding
New java.util.Base64 class allows encoding and decoding Base64 strings.
✅ Example:
import java.util.Base64;
public class Base64Example {
public static void main(String[] args) {
String text = "Hello, Java 8!";
String encoded = Base64.getEncoder().encodeToString(text.getBytes());
String decoded = new String(Base64.getDecoder().decode(encoded));
System.out.println("Encoded: " + encoded);
System.out.println("Decoded: " + decoded);
}
}
10. Nashorn JavaScript Engine (Deprecated in Java 15)
Java 8 introduced Nashorn, a JavaScript engine for running JavaScript inside Java.
✅ Example:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornExample {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
engine.eval("print('Hello from JavaScript in Java');");
}
}
Note: Nashorn was removed in Java 15.




