TOP JAVA 8 FEATURES WITH EXAMPLES
- Gopika narra
- Apr 17, 2023
- 9 min read
Updated: Jul 12, 2024

TABLE OF CONTENTS
WHAT IS JAVA 8?
TOP JAVA 8 FEATURES
Functional Interfaces And Lambda Expressions
Default And Static Methods In Interfaces
forEach() Method In Iterable Interface
Java Stream API For Bulk Data Operations On Collections
Java Date Time API
Collection API Improvements
Java IO Improvements
Miscellaneous Core API Improvements
CONCLUSION
FAQ
WHAT IS JAVA 8?
Java 8 is a version of the Java programming language that was released by Oracle Corporation in March 2014. It is a major update to the Java language and introduced several new features and improvements to the platform Overall, Java 8 has many features and improvements that make it a popular choice for developers. Some of the notable features are discussed here.
TOP JAVA 8 FEATURES WITH EXAMPLES

FUNCTIONAL INTERFACE
This is an important feature of Java 8's support for functional programming. functional interfaces are interfaces that have only one abstract method, and they enable the use of lambda expressions and method references as function types in Java 8.
Note: - A functional interface can contain any number of static and default methods but must have only one abstract method.
interface FuncInterfaceDemo{
int void demo();
}
Some more Examples are:-
· java.lang.Runnable
· java. util.Comparator
· java.util.concurrent.Callable
· java.io.FileFilter
When a user declares a functional interface then there may be a chance of adding more abstract methods. So, to avoid this we use @FunctionalInterface annotation.The @FunctionalInterface annotation can be used to indicate that an interface is intended to be a functional interface, and the compiler will generate an error if the interface does not meet the requirements of a functional interface.
Here is an example of a functional interface that illustrate functional interface:
@FunctionalInterface
interface Computer{
void works();
default void display(){
System.out.println(“I am desktop!!”);
}
}
Class Laptop implements Computer{
Public void works(){
System.out.println(“I am lapi!!”);
}
}
Public class Main implements Demo{
Public static void main(String [] args){
Laptop l=new Laptop();
l.works();
}
}
output:-I am lapi!!
LAMBDA EXPRESSIONS
Lambda expressions are a feature introduced in Java 8 that provide a concise way to represent anonymous functions. They are a shorthand notation for implementing functional interfaces, which are interfaces with only one abstract method.
The three primary reasons why we need Java Lambda expressions are as follows:
· Lambda converts the code segment into an argument
· It is a method that can be created without instantiating a class
· Lambda can be treated as an Object
A lambda expression consists of the following components:
A comma-separated list of parameters enclosed in parentheses. For example: (int x, int y)
The arrow operator ->, which separates the parameter list from the body of the lambda expression. For example: ->
The body of the lambda expression, which can be a single expression or a block of statements enclosed in curly braces. For example: x + y or { return x + y; }
Syntax of a Java Lambda Expression is:-
([comma separated argument-list]) -> {body}.
For a better understanding go through the example below:-
@FunctionalInterface
interface Area{
int calculate(int n);
}
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
Area a=n-> n= n*2;
System.out.println(a.calculate(6));
}
}
OUTPUT:-12
DEFAULT AND STATIC METHODS IN INTERFACES
Default methods are a new feature introduced in Java 8 that allow interfaces to have non-abstract methods with default implementations.
Before Java 8, interfaces could only define abstract methods that had to be implemented by any class that implemented the interface. If an interface needed to be changed by adding a new method, all classes implementing that interface had to be modified to provide an implementation for the new method. This was a problem for backward compatibility.
Here is an example of an interface that defines a default method:
public interface Vehicle {
void start();
default void stop() {
System.out.println("Vehicle stopped.");
}
}
public class Car implements Vehicle {
public void start() {
System.out.println("Car started.");
}
public void stop() {
System.out.println("Car stopped.");
}
}
The class car implements the start() method from the Vehicle interface and provides its own implementation of the stop() method. When the stop() method is called on an instance of the Car class, the Car implementation will be used instead of the default implementation defined in the Vehicle interface.
Static methods in interfaces can be called directly on the interface, without the need for an implementing class instance. They are often used for utility methods that do not depend on the state of any particular object.
Here's an example of a static method in an interface:
interface Computer{
void calculate(int n);
static void demo(){
System.out.println(“hiii iam computer”);
}
}
Public class Laptop implements Computer{
Public static void main(String [] args){
Computer c=n->n=n*2;
System.out.println(c.calculate(6));
c.demo();
}
}
forEach( ) method in iterable interface
For-each is another array traversing technique like for loop, while loop, do-while loop introduced in Java5.
The forEach() method is a default method in the Iterable interface introduced in Java 8, which allows you to iterate over all the elements in a collection and perform an action on each element.
1. For-each loops are not appropriate when you want to modify the array.
2. For-each loops do not keep track of index. So we can not obtain array index using For-Each loop .
3. For-each only iterates forward over the array in single steps .
4. For-each cannot process two decision making statements at once .
5. For-each also has some performance overhead over simple iteration.
Here's an example of how to use forEach() method with an Iterable collection:
import java.util.*;
public class ForEachDemo {
public static void main(String[] args) {
List<Integer>nums=new ArrayList();
nums.add(10);
nums.add(20);
nums.add(0);
nums.forEach(n-> System.out.println(" i am good!"+n));
}
}
In the above example we added integer elements in to the arraylist called nums and forEach() method is called on the nums list, which implements the Iterable interface. A lambda expression is used as the argument to the forEach() method, which prints each element of the list to the console.
The output for the above code snippet is:
i am good!10
i am good!20
i am good!0
Note :- The forEach() is a terminal operation, which means that it performs an action on each element of the collection and returns void, without modifying the original collection.
STREAM API
The Stream API is a powerful new feature introduced in Java 8, which provides a concise and functional way of working with collections of data. It allows you to perform operations on a collection of data in a declarative manner, without the need for boilerplate code.
The Stream API provides a set of operations that can be applied to a stream of data, including filtering, mapping, sorting, and reducing.
The beauty of streams is that if we once use them we cannot use them again,
same as a stream of water i.e. if we touch a river stream once then we cannot touch the same stream again.
The Stream API in conjunction with lambda expressions can be used to perform bulk operations on Collections without the need for external iteration. The basic interface in the Stream API is called the 'java.util.Stream', and there are various methods on the Stream interface that perform various operations on the Stream instance.
if we use the same stream more than once it results in an exception as below:
“ Exception in thread "main" java. lang.IllegalStateException: stream has already been operated upon or closed at java. base/java.util.stream.AbstractPipeline.sourceStageSpliterator (AbstractPipeline.java:279)at java base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
Here's an example of how to use the Stream API to filter and map a list of integers:
import java.util.*;
public class StremApiDemo {
public static void main (String[] args) {
List<Integer> nums=Arrays.asList(2,3,89,7,11,5,0,4);
Stream <Integer> stream1=nums.stream();
Stream<Integer> stream2=stream1.filter(n-> n%2==1);
Stream<Integer> stream3=stream2.map(n-> n=n*2);
int res=stream3.reduce(0,(s,e)->s+e);
System.out.println(res);
}
}
Output: -230
In this example, we start by creating a list of integers. We then create a stream from this list using the stream() method the Stream.filter is used to filter the Stream and create a new Stream of odd numbers(Stream2). Then the code invokes the for Each method on the Stream. This method accepts a Consumer instance which is another in-built functional interface. Here, a lambda expression is used to implement the Consumer interface. This lambda expression accepts an integer value and simply prints it.
3,89,7,11,5.
The stream map is used to the Stream and creates a new Stream using the specified function. Then the code invokes the forEach method on the Stream. This method accepts a Function (Applies this function to the given argument.) which is another in-built functional interface. Here, a lambda expression is used to implement the specified function.
And the result is:-6,178,14,121,25.
After, our requirement is to add all the integers obtained in the above step.
Reduce takes two parameters: an identity (often called an “accumulator”) and a BinaryOperator to reduce to a single value. The way to understand this specific reduce function is “Starting with the number 0, sum all of the integers in the stream, and return that sum.”
The result is:230
Other operations that can be applied to a stream include sorted(), distinct(), limit(), skip(), and reduce().
Streams can also be parallelized by using the parallelstream () method instead of stream(), which will automatically partition the data and process it in parallel on multiple threads.
import java.util.*;
public class StremApiDemo {
public static void main (String[] args) {
List<Integer> nums=Arrays.asList(2,3,89,7,11,5,0,4);
int result=nums.parallelStream()
. filter (n -> n%2==1)
. map(n-> n*2)
.reduce(0,(s,e)-> s+e);
System.out.println("result is:"+result);
The Stream API provides a powerful and flexible way of working with collections of data in Java 8, making it easier to write concise, efficient, and readable code.
JAVA DATE AND TIME API
Prior to Java 8, working with dates and times in Java was done using the java.util.Date and java.util.Calendar classes, which were often cumbersome and error-prone. Java 8 introduced a new Date and Time API, known as the java.time package, that provides a more modern and intuitive way of working with dates and times.
LocalDate and LocalTime: -
The first classes you will probably encounter when using the new API are Local Date and Local Time. They are local in the sense that they represent date and time from the context of the observer, such as a calendar on a desk or a clock on your wall. There is also a composite class called LocalDateTime, which is a pairing of Local Date and Local Time.
// Java code for LocalDate
// LocalTime Function
import java.time.*;
import java.time.format.DateTimeFormatter;
public class Date {
public static void LocalDateTimeApi()
{
// the current date
LocalDate date = LocalDate.now();
System.out.println("the current date is "+date);
// the current time
LocalTime time = LocalTime.now();
System.out.println("the current time is "+time);
// will give us the current time and date
LocalDateTime current = LocalDateTime.now();
System.out.println("current date and time : "+current);
// to print in a particular format
DateTimeFormatter format =
DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formatedDateTime = current.format(format);
System.out.println("in formatted manner "+
formatedDateTime);
// printing months days and seconds
Month month = current.getMonth();
int day = current.getDayOfMonth();
int seconds = current.getSecond();
System.out.println("Month : "+month+" day : "+
day+" seconds : "+seconds);
// printing some specified date
LocalDate date2 = LocalDate.of(1950,1,26);
System.out.println("the republic day :"+date2);
// printing date with current time.
LocalDateTime specificDate =
current.withDayOfMonth(24).withYear(2016);
System.out.println("specific date with "+
"current time : "+specificDate);
}
// Driver code
public static void main(String[] args)
{
LocalDateTimeApi();
}
}
Output:- the current date is 2021-09-23 the current time is 20:52:39.954238 current date and time : 2021-09-23T20:52:39.956909 in formatted manner 23-09-2021 20:52:39 Month : SEPTEMBER day : 23 seconds : 39 the republic day :1950-01-26 specific date with current time : 2016-09-24T20:52:39.956909
Zoned date-time API : Use it when time zones are to be considered
// Java code for Zoned date-time API
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Zone {
// Function to get Zoned Date and Time
public static void ZonedTimeAndDate()
{
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter format1 =
DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formattedCurrentDate = date.format(format1);
System.out.println("formatted current Date and"+
" Time : "+formattedCurrentDate);
// to get the current zone
ZonedDateTime currentZone = ZonedDateTime.now();
System.out.println("the current zone is "+
currentZone.getZone());
// getting time zone of specific place
// we use withZoneSameInstant(): it is
// used to return a copy of this date-time
// with a different time-zone,
// retaining the instant.
ZoneId tokyo = ZoneId.of("Asia/Tokyo");
ZonedDateTime tokyoZone =
currentZone.withZoneSameInstant(tokyo);
System.out.println("tokyo time zone is " +
tokyoZone);
DateTimeFormatter format =
DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formatedDateTime = tokyoZone.format(format);
System.out.println("formatted tokyo time zone "+
formatedDateTime);
}
// Driver code
public static void main(String[] args)
{
ZonedTimeAndDate();
}
}
CONCLUSION
Overall, Java 8 was a significant and highly impactful release of the Java programming language, providing developers with a wide range of new tools and features for building high-quality applications. It has greatly improved the Java ecosystem and helped to make Java a more modern and competitive language in the rapidly evolving world of software development.
FREQUENTLY ASKED QUESTIONS
1. What are the key features of Java 8?
The key features of Java 8 include lambda expressions, the Stream API, the Date and Time API, default methods in interfaces, the Optional class, and type annotations.
2. What are lambda expressions in Java 8?
Lambda expressions in Java 8 are a way of writing concise and functional code, allowing for the definition of anonymous functions that can be passed around and used as values.
3. What is the Stream API in Java 8?
The Stream API in Java 8 is a functional and declarative way of working with collections of data, providing a set of operations that can be applied to a stream of data.
4. What is the Date and Time API in Java 8?
The Date and Time API in Java 8 is a more modern and intuitive way of working with dates and times, with comprehensive support for time zones and other features.
5. What are default methods in interfaces in Java 8?
Default methods in interfaces in Java 8 are a way of adding new methods to interfaces without breaking existing implementations.
6.why developers still choose java8?
There are several reasons,some of them are:
Stability: Java 8 has been around for a long time and is a stable and well-established version of Java. Many organizations rely on Java 8 for their critical applications and prefer to stick with a stable and proven version.
Compatibility: java 8 is highly compatible with existing code and libraries,making it easy t upgrade existing applications to java 8 without any major changes.
Performance: Java 8 introduced several performance improvements, such as the Stream API, which can help to improve the performance of Java applications.
Comments