In Java, the Stream API was introduced in Java 8 to provide a modern way of working with collections and other data sources. Streams allow you to perform operations like filtering, mapping, reducing, and collecting data from collections in a declarative way.
1. Creating a Stream
You can create a stream from a collection (e.g., List, Set) using the .stream()
method.
import java.util.List;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Charlie", "David");
// Create a stream from the List
Stream<String> nameStream = names.stream();
// Print the elements
nameStream.forEach(System.out::println);
}
}
2. Stream Operations
The Stream API supports a wide range of operations. These operations can be classified into intermediate and terminal operations.
Intermediate Operations
Intermediate operations are lazy (they don’t process the data until a terminal operation is invoked). They return a new stream and can be chained.
-
filter(): Filters elements based on a condition.
-
map(): Transforms elements.
-
sorted(): Sorts the stream.
-
distinct(): Removes duplicates.
-
peek(): Allows you to perform a non-interfering action (like logging) without modifying the stream.
Terminal Operations
Terminal operations trigger the processing of the stream and produce a result, such as a value or side-effect.
-
forEach(): Iterates over each element of the stream.
-
collect(): Collects the elements into a collection (like a List, Set).
-
reduce(): Performs a reduction on the stream (like summing values).
-
count(): Returns the number of elements in the stream.
-
anyMatch(), allMatch(), noneMatch(): Matches elements based on a condition.
Example of collect() and reduce():import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// Collecting to a List
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // Output: [2, 4]
// Using reduce() to sum the numbers
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
sum.ifPresent(System.out::println); // Output: 15
}
}
3. Chaining Stream Operations
One of the most powerful features of the Stream API is the ability to chain multiple operations together.import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Charlie", "David");
// Chaining operations: filter, map, sorted, collect
List<String> result = names.stream()
.filter(name -> name.length() > 3) // Filter names with length > 3
.map(String::toUpperCase) // Convert to uppercase
.sorted() // Sort alphabetically
.collect(Collectors.toList()); // Collect into a List
System.out.println(result); // Output: [ALICE, CHARLIE, DAVID]
}
}
4. Parallel Streams
The Stream API also supports parallel processing. Using parallelStream()
allows you to process elements in parallel across multiple threads, which can improve performance for large collections.
import java.util.List;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Parallel stream to sum numbers
int sum = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum: " + sum); // Output: 55
}
}
5. Short-Circuiting Operations
Some operations are short-circuiting, meaning they may not process all elements of the stream.
-
anyMatch(): Returns
true
if any element matches the condition. -
allMatch(): Returns
true
if all elements match the condition. -
noneMatch(): Returns
true
if no elements match the condition. -
findFirst(): Returns the first element in the stream.
findAny(): Returns any element (could be parallel) in the stream.
Summary of Key Methods
-
Intermediate Operations:
filter()
,map()
,sorted()
,distinct()
,peek()
-
Terminal Operations:
forEach()
,collect()
,reduce()
,count()
,anyMatch()
,allMatch()
-
Parallel Streams:
parallelStream()
-
Short-Circuiting Operations:
anyMatch()
,allMatch()
,findFirst()
The Stream API is highly versatile, and by combining different operations, you can perform a wide range of data transformations and processing tasks on collections in Java.
Comparator and compare in java with example using streams Java 8
In Java, Comparator
is an interface that is used to compare two objects. It is often used to define custom sorting orders for collections, and it's especially useful when working with the Stream API. The compare()
method is part of the Comparator
interface and is used to compare two objects.
Here's how they work:
-
compare(T o1, T o2)
: This method compares two objectso1
ando2
of typeT
. It returns: A negative integer if
o1
is less thano2
-
Zero if
o1
is equal too2
-
A positive integer if
o1
is greater thano2.
Using
Comparator
with CollectionsThe
Comparator
interface can be used to sort or order elements in a collection. Here's a basic example of usingComparator
with theStream
API.Example 1: Sorting a List of Strings using a Comparator
In this example:
-
We use
Comparator.comparingInt(String::length)
to create a comparator that compares the strings based on their length. -
The
sorted()
method of the stream uses this comparator to order the strings by length.
2. Using Comparator
with compare()
You can also directly create a Comparator
by implementing the compare()
method. Here's an example of comparing Person
objects based on their age
field.
Example 2: Custom Comparator with compare()
Method
In this example:
-
We define a custom
Comparator<Person>
using thecompare()
method to comparePerson
objects based on theirage
. -
The
Integer.compare()
method is used in thecompare()
method to compare the ages, which is a clean and safe way to compare integer values.
3. Using Comparator
with reversed()
and Other Methods
You can also use Comparator
's built-in methods like reversed()
, thenComparing()
, and others to modify how comparisons are done.
Example 3: Reversing Order and Chaining Comparators
import java.util.*;
import java.util.stream.*;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35),
new Person("David", 28)
);
// Sort first by age, then by name in reversed order
List<Person> sortedByAgeAndName = people.stream()
.sorted(Comparator.comparingInt(Person::getAge)
.thenComparing(Person::getName)
.reversed()) // Reversing the entire order
.collect(Collectors.toList());
System.out.println("Sorted by age and reversed name: " + sortedByAgeAndName);
}
}
In this example:
-
We first sort by
age
usingComparator.comparingInt(Person::getAge)
. -
We then chain another comparator using
thenComparing(Person::getName)
to sort byname
. -
Finally, we reverse the order of the entire comparator using
.reversed()
.
4. Using Comparator
with comparing()
for Complex Fields
You can use the Comparator.comparing()
method to simplify comparisons, especially when dealing with more complex types like String
or Date
.
Example:
import java.util.*;
import java.util.stream.*;
class Person {
String name;
int age;
String city;
public Person(String name, int age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return name + " (" + age + ", " + city + ")";
}
}
public class ComparatorExample {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 30, "New York"),
new Person("Bob", 25, "Los Angeles"),
new Person("Charlie", 35, "Chicago"),
new Person("David", 28, "San Francisco")
);
// Sort by city name then by age
List<Person> sortedByCityAndAge = people.stream()
.sorted(Comparator.comparing(Person::getCity)
.thenComparingInt(Person::getAge))
.collect(Collectors.toList());
System.out.println("Sorted by city and age: " + sortedByCityAndAge);
}
}
In this example:
-
We first sort by
city
usingComparator.comparing(Person::getCity)
. -
We then chain a second comparator to sort by
age
usingthenComparingInt(Person::getAge)
.
Summary of Key Methods:
-
compare(T o1, T o2)
: Compares two objects of typeT
.Comparator.comparing()
: A static method to create a comparator based on a specific field or property.-
thenComparing()
: Allows chaining comparators to compare by multiple criteria. -
reversed()
: Reverses the order of a comparator. -
comparingInt()
,comparingDouble()
,comparingLong()
: Specialized methods for comparing primitive types.
By using these methods, you can easily sort or compare complex data structures using Java's
Stream
API andComparator
interface.
No comments:
Post a Comment