Exploring Java 8 Features

Rakesh singhania
4 min readAug 26, 2023

--

In the realm of programming, Java 8 takes in a new era with its groundbreaking features that revolutionized the way developers crafted code. This guide will dive into the innovations Java 8 brought to the table, accompanied by illustrative examples that shed light on their practical applications.

Lambda Expressions: Crafting Elegance in Code

One of the crown jewels of Java 8 is the introduction of lambda expressions. These concise and expressive entities enable developers to encapsulate functions as objects, allowing for a more streamlined and flexible coding experience.

  public static void main(String[] args) {
List<String> names = Arrays.asList("Rakesh", "Anurag", "Anil");
names.forEach(name -> System.out.println("Hello, " + name));
}

Stream API: Unleashing Data Processing Potential

The Stream API breathed life into data manipulation by providing a fluent and declarative approach to processing sequences of elements.

Here’s a glimpse into the power of streams:


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum of even numbers: " + sum);
}

// In real world you can use expression like this 
// in this we are finding all targets and mapping to DTO and finally
// collecting to list
return ResponseEntity.ok(targetService.findAll().stream()
.map(TargetDto::buildWithTarget)
.collect(Collectors.toList()));

Default Methods: Evolving Interfaces

Java 8 introduced the concept of default methods in interfaces, enabling developers to enhance interface functionality without breaking implementations. This is particularly useful for backward compatibility

interface Shape {
// Existing method
void draw();
// new default method to use in implementing classes
default void description() {
System.out.println("This is a shape.");
}
}

Functional Interfaces: Power of Single Abstract Method

Functional interfaces gained popularity with Java 8’s focus on lambda expressions. These interfaces have a single abstract method, facilitating the use of lambdas for concise code:

@FunctionalInterface
interface Calculator {
int operate(int a, int b);
}

// calculate
public class Main {
public static void main(String[] args) {

Calculator calculator = (x, y) -> x + y;
int result = calculator.operate(10, 20);
System.out.println(result); // 30


Calculator minusCalculator = (x, y) -> x - y;
int resultMinus = minusCalculator.operate(30, 20);
System.out.println(resultMinus); // 10
}
}

Method References: A Link to Simplicity

Method references provide a concise syntax for invoking methods as lambda expressions. This simplifies code and enhances readability:

List<String> names = Arrays.asList("Rakesh", "kumar", "Anil");
// use method reference directly by ::
names.forEach(System.out::println);

Optional: Mitigating Null Woes

Handling null values became less cumbersome with the Optional class. It encourages developers to explicitly consider the absence of a value:

Optional<String> name = Optional.ofNullable(getName());
System.out.println(name.orElse("Name not available."));

Time API: Managing Time

Java 8’s Time API revamped date and time handling. The LocalDate and LocalDateTime classes offer clarity and precision in temporal operations:

    LocalDate.of(2023, 8, 21);

LocalDate today=LocalDate.parse("2023-08-21");
DayOfWeek week = today.getDayOfWeek();
System.out.println(week); //MONDAY

LocalDate tomorrow = LocalDate.now().plusDays(1);
System.out.println(tomorrow); //2023-08-27

LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);
System.out.println(previousMonthSameDay); //2023-07-26

boolean leapYear = LocalDate.now().isLeapYear();
System.out.println(leapYear); //false

boolean isBefore = LocalDate.parse("2023-08-21")
.isBefore(LocalDate.parse("2023-08-22"));
System.out.println(isBefore); //true

Exception Handling Improvements: Streamlining Errors

Java 8 brought enhancements to exception handling with the introduction of the Throwable class. This class simplifies catching and handling multiple exceptions within a single catch block:

try {
// Code that may throw exceptions
} catch (IOException | SQLException e) {
// Handling multiple exceptions
System.err.println("An error occurred: " + e.getMessage());
}

Compact Profiles: Tailoring for Efficiency

To cater to diverse platforms and devices, Java 8 introduced compact profiles. These are subsets of the Java SE platform optimized for specific use cases, reducing the memory footprint:

import java.util.Optional;
import java.util.stream.Stream;

public class CompactProfileExample {

public static void main(String[] args) {

Optional<String> message = Stream.of("Hello", "Rakesh")
.reduce((s1, s2) -> s1 + " " + s2);

message.ifPresent(System.out::println);
}
}

Nashorn JavaScript Engine: A Bridge to the Web

Java 8 included the Nashorn JavaScript engine for seamless interaction between Java and JavaScript code. This improved integration facilitated web development and scripting tasks:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class NashornExample {
public static void main(String[] args) throws ScriptException {
// Initialize javascipt engine
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("nashorn");

engine.eval("print('Hello from Nashorn!')");
}
}

Parallelism: Unleashing Multithreaded Power

Java 8 introduced parallelism with the parallelStream() method, enabling effortless parallel processing of collections. This boosts performance by utilizing multiple cores:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum of numbers using parallelStream(): " + sum);

Method Parameter Reflection: Insightful Interactions

Java 8 introduced a more flexible approach to reflection with method parameter reflection. This allows you to examine method parameters dynamically:


public static void main(String[] args) throws NoSuchMethodException {
// get all methods of class via reflection
Method method = Main.class.getMethod("getMessage", String.class);
Parameter parameter = method.getParameters()[0];
//get parameters
System.out.println("Method parameter name: " + parameter.getName());
}


public void getMessage(String message) {
System.out.println("Message: " + message);
}

CompletableFuture: Asynchronous Excellence

Java 8 introduced the CompletableFuture class, enabling asynchronous programming with exceptional simplicity. This is particularly valuable for tasks that involve I/O operations:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> "Hello");

future.thenAccept(result -> System.out.println("Received: " + result));
}
}

Happy learning .!!

--

--

Rakesh singhania

As a student of technology, each day I take a single step forward on the path of learning.