0% found this document useful (0 votes)
8 views19 pages

Java 8 Features Notes

Uploaded by

only4study001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views19 pages

Java 8 Features Notes

Uploaded by

only4study001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Java 8 Feature[Important Only]

Lambda Expressions in Java

1. Concept

What is a Lambda Expression?


A Lambda Expression is a concise way to represent an anonymous function (a
function without a name) that can be passed as a parameter or assigned to a
variable. It allows writing more concise and functional-style code, introduced in
Java 8.

Why Do We Need Lambda Expressions?


1. Simplifies Code: Reduces the verbosity of anonymous inner classes.

2. Functional Programming: Enables functional-style programming in Java.

3. Improves Readability: Code becomes cleaner and easier to understand.

4. Reusability: Functions can be reused as behavior without wrapping them into


full classes.

2. How Does It Work?

Syntax
The syntax of a lambda expression is:

(parameters) -> expression


(parameters) -> { statements; }

Key Components

Java 8 Feature[Important Only] 1


1. Parameters: Represent the input to the lambda expression (can be omitted if
there is a single parameter).

2. Arrow Token ( > ): Separates parameters from the body.

3. Body: The logic of the lambda, which can be a single expression or a block of
statements.

Example:

(int a, int b) -> a + b

3. Detailed Example

Using Anonymous Inner Class

import java.util.ArrayList;
import java.util.List;

public class AnonymousInnerClassExample {


public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

// Using Anonymous Inner Class


names.forEach(new java.util.function.Consumer<String>
() {
@Override
public void accept(String name) {
System.out.println(name);
}

Java 8 Feature[Important Only] 2


});
}
}

Using Lambda Expression

import java.util.ArrayList;
import java.util.List;

public class LambdaExample {


public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

// Using Lambda Expression


names.forEach(name -> System.out.println(name));
}
}

4. Explanation of Lambda Code


1. Before (Verbose Code):

An anonymous inner class is created to implement the Consumer functional


interface.

This is verbose and requires additional boilerplate code.

2. After (Concise Code):

The lambda expression directly passes behavior ( name ->

System.out.println(name) ) as an argument.

Java 8 Feature[Important Only] 3


Eliminates the need for boilerplate code like new Consumer<String>() .

5. Key Use Cases

1. Functional Interfaces
Lambda expressions work only with functional interfaces (interfaces with a single
abstract method).

Example: Functional Interface

@FunctionalInterface
interface Greeting {
void sayHello(String name);
}

public class FunctionalInterfaceExample {


public static void main(String[] args) {
// Using Lambda
Greeting greeting = name -> System.out.println("Hell
o, " + name);
greeting.sayHello("Alice");
}
}

2. Collections
Lambdas simplify operations on collections.

Example: Filtering a List

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

Java 8 Feature[Important Only] 4


public class FilterExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

// Using Stream with Lambda


List<Integer> evenNumbers = numbers.stream()
.filter(num -> num
% 2 == 0)
.collect(Collector
s.toList());

System.out.println("Even Numbers: " + evenNumbers);


}
}

3. Custom Sorting
Lambdas are useful for custom sorting using Comparator .

Example: Sorting Names by Length

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SortingExample {


public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

// Custom Sorting
Collections.sort(names, (name1, name2) -> name1.lengt

Java 8 Feature[Important Only] 5


h() - name2.length());

System.out.println("Sorted by Length: " + names);


}
}

6. Advanced Lambda Features

Method References
A method reference is a shorthand for a lambda that calls a specific method. It is
represented by ClassName::methodName .

Example:

import java.util.Arrays;

public class MethodReferenceExample {


public static void main(String[] args) {
String[] names = {"Alice", "Bob", "Charlie"};

// Using Method Reference


Arrays.stream(names).forEach(System.out::println);
}
}

Capturing Variables
Lambdas can capture local variables (effectively final).

Example:

public class VariableCaptureExample {

Java 8 Feature[Important Only] 6


public static void main(String[] args) {
String greeting = "Hello";

Runnable runnable = () -> System.out.println(greetin


g); // Captures 'greeting'
runnable.run();
}
}

7. Advantages of Lambda Expressions


1. Conciseness: Eliminates boilerplate code.

2. Improved Readability: Code is cleaner and easier to understand.

3. Functional Programming: Enables a declarative coding style.

4. Compatibility: Works seamlessly with Java's existing APIs like Streams .

8. Limitations of Lambda Expressions


1. Single Abstract Method: Works only with functional interfaces.

2. Readability with Complex Logic: Lambdas with complex bodies may reduce
readability.

3. Debugging: Debugging inside a lambda expression can be challenging.

Functional Interfaces in Java

What is a Functional Interface?


A functional interface in Java is an interface that contains exactly one abstract
method. Functional interfaces are used to represent a single functionality and are
primarily intended for lambda expressions and method references.

Java 8 Feature[Important Only] 7


Definition: An interface with one and only one abstract method is called a
functional interface.

Purpose: To enable functional programming in Java by using lambda


expressions to represent instances of functional interfaces.

Key Points:

Annotated with @FunctionalInterface (optional but recommended for clarity).

Can have default and static methods, but only one abstract method.

Why Functional Interfaces?


1. Lambda Support: Enables lambda expressions, making code concise and
readable.

2. Improved Readability: Reduces boilerplate code in comparison to anonymous


classes.

3. Standardized Patterns: Simplifies implementation of common operations like


filtering, mapping, consuming, or supplying data.

4. Built-In Functional Interfaces: Java 8 introduced many functional interfaces in


the java.util.function package for common use cases.

Concept and Example of Functional Interfaces


Example: Custom Functional Interface

@FunctionalInterface
interface MyFunctionalInterface {
void display(String message);
}

public class FunctionalInterfaceExample {


public static void main(String[] args) {
// Using a lambda expression to implement the interfa
ce

Java 8 Feature[Important Only] 8


MyFunctionalInterface example = (message) -> System.o
ut.println(message);
example.display("Hello, Functional Interface!");
}
}

Explanation:

MyFunctionalInterface has a single abstract method display .

A lambda expression (message) -> System.out.println(message) is used to


implement it.

Common Functional Interfaces


Java provides several built-in functional interfaces in the java.util.function

package. Let’s explore the commonly used ones:

1. Predicate<T>
Definition: Represents a function that takes one argument and returns a
boolean value.

Purpose: Used for filtering or testing conditions.

Abstract Method: boolean test(T t)

Example: Filtering Even Numbers

import java.util.function.Predicate;
import java.util.Arrays;
import java.util.List;

public class PredicateExample {


public static void main(String[] args) {
Predicate<Integer> isEven = (number) -> number % 2 ==
0;

Java 8 Feature[Important Only] 9


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5,
6);
numbers.stream()
.filter(isEven) // Apply the Predicate
.forEach(System.out::println); // Output: 2,
4, 6
}
}

Explanation:

The isEven Predicate checks whether a number is even.

Used with filter to process a stream of numbers.

2. Function<T, R>
Definition: Represents a function that takes one argument of type T and
returns a result of type R .

Purpose: Used for data transformation.

Abstract Method: R apply(T t)

Example: Transforming Strings to Uppercase

import java.util.function.Function;
import java.util.Arrays;
import java.util.List;

public class FunctionExample {


public static void main(String[] args) {
Function<String, String> toUpperCase = (input) -> inp
ut.toUpperCase();

List<String> names = Arrays.asList("alice", "bob", "c

Java 8 Feature[Important Only] 10


harlie");
names.stream()
.map(toUpperCase) // Apply the Function
.forEach(System.out::println); // Output: ALICE,
BOB, CHARLIE
}
}

Explanation:

The toUpperCase Function transforms a string to uppercase.

Used with map to process each element in the list.

3. Consumer<T>
Definition: Represents a function that takes one argument and performs an
operation without returning a result.

Purpose: Used for performing actions like logging or printing.

Abstract Method: void accept(T t)

Example: Printing a List

import java.util.function.Consumer;
import java.util.Arrays;
import java.util.List;

public class ConsumerExample {


public static void main(String[] args) {
Consumer<String> printName = (name) -> System.out.pri
ntln("Hello, " + name);

List<String> names = Arrays.asList("Alice", "Bob", "C


harlie");
names.forEach(printName); // Output: Hello, Alice; He

Java 8 Feature[Important Only] 11


llo, Bob; Hello, Charlie
}
}

Explanation:

The printName Consumer performs an action (printing) for each input.

Used with forEach to process a list of names.

4. Supplier<T>
Definition: Represents a function that takes no arguments and supplies a
result.

Purpose: Used for providing or generating data.

Abstract Method: T get()

Example: Supplying a Random Number

import java.util.function.Supplier;
import java.util.Random;

public class SupplierExample {


public static void main(String[] args) {
Supplier<Integer> randomNumberSupplier = () -> new Ra
ndom().nextInt(100);

System.out.println("Random Number: " + randomNumberSu


pplier.get());
}
}

Explanation:

Java 8 Feature[Important Only] 12


The randomNumberSupplier Supplier generates a random number.

Used with get() to retrieve the result.

Comparison of Functional Interfaces


Interface Arguments Return Type Use Case
Predicate<T> 1 boolean Testing conditions or filtering.
Function<T,R> 1 R Transforming data.

Performing operations like


Consumer<T> 1 void
printing/logging.
Supplier<T> 0 T Supplying or generating data.

Streams API in Java

What is the Streams API?


The Streams API in Java, introduced in Java 8, provides a powerful way to
process collections of data in a functional and declarative style. It simplifies
operations such as filtering, mapping, and reducing collections of data by chaining
operations to form pipelines.

Why Streams API?


1. Improved Readability: Simplifies complex data manipulation tasks with
functional-style programming.

2. Efficiency: Supports parallel processing for better performance.

3. Flexibility: Processes data without modifying the underlying source.

4. Laziness: Intermediate operations are lazy, meaning they don’t execute until a
terminal operation is invoked.

Concepts of Streams API

Java 8 Feature[Important Only] 13


Stream: A sequence of elements supporting sequential and parallel
operations.

Pipeline: Consists of:

Source: Input data (e.g., List , Set , Map , arrays).

Intermediate Operations: Transform or filter the data (e.g., map , filter ).

Terminal Operations: Produce a result or a side effect (e.g., collect ,


forEach ).

Example of Streams API

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamsExample {


public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "C
harlie", "David");

// Using Streams API to filter and transform data


List<String> filteredNames = names.stream()
.filter(name -> nam
e.startsWith("C"))
.map(String::toUppe
rCase)
.collect(Collector
s.toList());

System.out.println(filteredNames); // Output: [CHARLI


E]
}

Java 8 Feature[Important Only] 14


}

Explanation:

Source: names list.

Intermediate Operations:

filter : Filters names that start with "C".

map : Converts filtered names to uppercase.

Terminal Operation:

collect : Collects the result into a list.

Intermediate Operations
Definition: Intermediate operations are used to transform a stream, and they are
lazy, meaning they are not executed until a terminal operation is applied.

Common Intermediate Operations


1. map : Transforms each element in the stream.

2. filter : Filters elements based on a condition.

3. sorted : Sorts elements in natural or custom order.

Code Examples:

1. map :

import java.util.Arrays;
import java.util.List;

public class MapExample {


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squaredNumbers = numbers.stream()
.map(n -> n *

Java 8 Feature[Important Only] 15


n)
.collect(Collec
tors.toList());
System.out.println(squaredNumbers); // Output: [1, 4,
9, 16, 25]
}
}

1. filter :

import java.util.Arrays;
import java.util.List;

public class FilterExample {


public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "C
harlie", "David");
List<String> shortNames = names.stream()
.filter(name -> name.l
ength() <= 3)
.collect(Collectors.to
List());
System.out.println(shortNames); // Output: [Bob]
}
}

1. sorted :

import java.util.Arrays;
import java.util.List;

Java 8 Feature[Important Only] 16


public class SortedExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collect
ors.toList());
System.out.println(sortedNumbers); // Output: [1, 2,
3, 5, 8]
}
}

Terminal Operations
Definition: Terminal operations produce a result or a side-effect and trigger the
execution of the entire stream pipeline.

Common Terminal Operations


1. collect : Collects the elements of the stream into a collection.

2. forEach : Performs an action for each element in the stream.

3. reduce : Reduces the stream to a single value by combining elements.

Code Examples:

1. collect :

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class CollectExample {


public static void main(String[] args) {

Java 8 Feature[Important Only] 17


List<String> names = Arrays.asList("Alice", "Bob", "C
harlie", "Alice");
Set<String> uniqueNames = names.stream()
.collect(Collectors.to
Set());
System.out.println(uniqueNames); // Output: [Alice, B
ob, Charlie]
}
}

1. forEach :

import java.util.Arrays;
import java.util.List;

public class ForEachExample {


public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.forEach(System.out::println); // Output: 1,
2, 3, 4, 5
}
}

1. reduce :

import java.util.Arrays;
import java.util.List;

public class ReduceExample {


public static void main(String[] args) {

Java 8 Feature[Important Only] 18


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println(sum); // Output: 15
}
}

Method References
Definition: Simplifies lambda expressions by referring to existing methods.

Types:

Reference to a static method: ClassName::staticMethod

Reference to an instance method: instance::method

Reference to a constructor: ClassName::new

Example:

import java.util.Arrays;

String[] names = { "Alice", "Bob", "Charlie" };


// Using method reference
Arrays.sort(names, String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));

Java 8 Feature[Important Only] 19

You might also like