Java Stream Methods : For Solving Many Problems On Leetcode & CodeChef.
7 Java Coding Hacks For Efficient Coding :
Java Stream API is used to perform functional-style operations on collections of elements, such as arrays or lists, and provides a way to write more concise, readable, and maintainable code. The Java Streams API allows us to perform aggregate operations on data in a declarative way, without needing to write low-level imperative code to traverse collections.
Here are some reasons why we use Java Stream API:
- Declarative and functional programming style: Java Streams API provides a more declarative and functional way to operate on collections, rather than using for loops, if statements, and other low-level imperative code. This makes code more concise and easier to read and understand.
- Parallelism and performance: Java Streams API provides an easy way to parallelize operations on collections, making it easier to take advantage of multi-core processors and improve performance.
- Code reuse and composability: Java Streams API provides a set of reusable, composable operations that can be combined to create more complex operations. This can help reduce code duplication and improve maintainability.
- Interoperability: Java Streams API can be used with other Java APIs, such as Lambda expressions and Method references, making it easier to integrate with existing code and libraries.
Overall, the Java Streams API is a powerful and flexible tool for processing collections of data in a declarative, functional way, and can help make code more readable, maintainable, and performant.
We use Java Stream API methods to perform functional-style operations on collections of elements, such as arrays or lists. The Java Streams API provides a set of operations that can be chained together to perform various transformations and actions on the data, including filtering, mapping, reducing, and more.
Here are some common Java Stream API methods and their examples:
filter()
: This method is used to filter elements based on a specified condition. For example, to filter even numbers from an array of integers, you can use the following code:
filter()
: Returns a stream with elements that match a given predicate.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers); // prints [2, 4]
int[] arr = {1, 2, 3, 4, 5, 6};
Arrays.stream(arr)
.filter(n -> n % 2 == 0)
.forEach(System.out::println); // prints 2, 4, 6
2. map()
: This method is used to transform each element in a stream to a new value. For example, to square each element in an array of integers, you can use the following code:
map()
: Returns a stream with the results of applying a given function to each element in the stream.
List<String> names = Arrays.asList("John", "Mary", "Tom", "Jerry");
List<Integer> nameLengths = names.stream().map(String::length).collect(Collectors.toList());
System.out.println(nameLengths); // prints [4, 4, 3, 5]
int[] arr = {1, 2, 3, 4, 5};
Arrays.stream(arr)
.map(n -> n * n)
.forEach(System.out::println); // prints 1, 4, 9, 16, 25
3. reduce()
: This method is used to reduce the elements in a stream to a single value. For example, to find the sum of elements in an array of integers, you can use the following code:
reduce()
: Reduces the elements in the stream to a single value by applying a binary operator to the elements.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().reduce(Integer::sum);
System.out.println(sum); // prints 15
int[] arr = {1, 2, 3, 4, 5};
int sum = Arrays.stream(arr)
.reduce(0, (a, b) -> a + b);
System.out.println(sum); // prints 15
4.distinct()
: This method is used to remove duplicates from a stream. For example, to find unique elements in an array of integers, you can use the following code:
distinct()
: Returns a stream with distinct elements. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 4, 5, 1);
List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList());
System.out.println(distinctNumbers); // prints [1, 2, 3, 4, 5]
int[] arr = {1, 2, 3, 2, 4, 5, 1};
Arrays.stream(arr)
.distinct()
.forEach(System.out::println); // prints 1, 2, 3, 4, 5
5. sorted()
: This method is used to sort the elements in a stream. For example, to sort an array of integers in ascending order, you can use the following code:
sorted()
: Returns a stream with the elements sorted according to a given comparator.
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);
List<Integer> sortedNumbers = numbers.stream().distinct().sorted().collect(Collectors.toList());
System.out.println(sortedNumbers); // prints [1, 2, 3, 4, 5, 6, 9]
int[] arr = {5, 2, 8, 3, 1};
Arrays.stream(arr)
.sorted()
.forEach(System.out::println); // prints 1, 2, 3, 5, 8j
6. allMatch()
: Returns true
if all elements in the stream match a given predicate, otherwise returns false
. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
System.out.println(allEven); // prints false
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEven = numbers.stream()
.allMatch(n -> n % 2 == 0);
System.out.println(allEven); // prints false
7. anyMatch()
: Returns true
if any element in the stream matches a given predicate, otherwise returns false
. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
System.out.println(anyEven); // prints true
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream()
.anyMatch(n -> n % 2 == 0);
System.out.println(anyEven); // prints true
8. collect()
: Performs a mutable reduction operation on the elements of the stream, such as converting a stream to a list or a map. Example:
List<String> names = Arrays.asList("John", "Mary", "Tom", "Jerry");
List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperCaseNames); // prints ["JOHN", "MARY", "TOM", "JERRY"]
9. count()
: Returns the number of elements in the stream. Example:
List<String> names = Arrays.asList("John", "Mary", "Tom", "Jerry");
long count = names.stream().count();
System.out.println(count); // prints 4
10. findAny()
: Returns an arbitrary element from the stream, if any. Example:
findAny()
Returns an Optional
containing any element of the stream, or an empty Optional
if the stream is empty. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstNumber = numbers.stream().findFirst();
System.out.println(firstNumber); // prints Optional[1]
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> anyNumber = numbers.stream().findAny();
System.out.println(anyNumber); // prints an arbitrary number
11. findFirst()
: Returns the first element in the stream, if any. Example:
findAny()
: Returns an Optional
containing any element of the stream, or an empty Optional
if the stream is empty. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> anyNumber = numbers.stream().findAny();
System.out.println(anyNumber); // prints Optional[1] or some other number
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstNumber = numbers.stream().findFirst();
System.out.println(firstNumber); // prints 1
12. flatMap()
: Returns a stream that is a result of flattening a stream of streams.
flatMap()
: Returns a stream consisting of the results of replacing each element of the stream with a stream of mapped elements. Example:
List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
List<Integer> flattenedList = nestedList.stream().flatMap(List::stream).collect(Collectors.toList());
System.out.println(flattenedList); // prints [1, 2, 3, 4, 5, 6]
List<Integer> flattenedNumbers = numbers.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(flattenedNumbers); // prints [1, 2, 3, 4, 5, 6]
13. forEach()
: Performs an action on each element in the stream. Example:
List<String> names = Arrays.asList("John", "Mary", "Tom", "Jerry");
names.stream().forEach(System.out::println); // prints each name on a separate line
14. limit()
: Returns a stream with the specified number of elements. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limitedNumbers = numbers.stream().limit(3).collect(Collectors.toList());
System.out.println(limitedNumbers); // prints [1, 2, 3]
15. max()
: Returns the maximum element in the stream according to a given comparator. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> maxNumber = numbers.stream().max(Integer::compare);
System.out.println(maxNumber); // prints 5
16. min()
: Returns the minimum element in the stream according to a given comparator. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> minNumber = numbers.stream().min(Integer::compare);
System.out.println(minNumber); // prints 1
17. noneMatch()
: Returns true
if none of the elements in the stream match a given predicate, otherwise returns false
.
noneMatch()
: Returns whether no elements of the stream match the provided predicate. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);
System.out.println(noneNegative); // prints true
18. of()
: Returns a stream with the specified elements. Example:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);
List<Integer> numberList = numbers.collect(Collectors.toList());
System.out.println(numberList); // prints [1, 2, 3, 4, 5]
19. peek()
: Returns a stream with the same elements as the original stream, but with an action performed on each element as it is consumed. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream()
.peek(n -> System.out.print(n + " "))
.map(n -> n * 2)
.peek(n -> System.out.print(n + " "))
.collect(Collectors.toList());
System.out.println(result); // prints [2, 4, 6, 8, 10]
List<String> names = Arrays.asList("John", "Mary", "Tom", "Jerry");
List<String> upperCaseNames = new ArrayList<>();
List<String> collectedNames = names.stream().peek(name -> upperCaseNames.add(name.toUpperCase())).collect(Collectors.toList());
System.out.println(collectedNames); // prints ["John", "Mary", "Tom", "Jerry"]
System.out.println(upperCaseNames);
20. toArray()
: Returns an array containing the elements of the stream. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Integer[] numberArray = numbers.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(numberArray)); // prints [1, 2, 3, 4, 5]
21. skip()
: Returns a stream with the specified number of elements skipped. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skippedNumbers = numbers.stream().skip(3).collect(Collectors.toList());
System.out.println(skippedNumbers); // prints [4, 5]
22. takeWhile()
: Returns a stream containing the elements of the stream up to the first element that does not match the specified predicate. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> result = numbers.stream().takeWhile(n -> n < 4).collect(Collectors.toList());
System.out.println(result); // prints [1, 2, 3]
23. dropWhile()
: Returns a stream containing the remaining elements of the stream after dropping the elements that match the specified predicate. Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> result = numbers.stream().dropWhile(n -> n < 4).collect(Collectors.toList());
System.out.println(result); // prints [4, 5, 6]
These are some more examples of methods available in the Java Stream API. While it’s not necessary to memorize all of the methods, it’s helpful to have an understanding of what’s available and how they can be used. By using the Stream API, you can write concise and efficient code for working with collections of data in Java.
Is it an efficient way to solve all problem by using stream method in java ?
While the Stream API can be a powerful tool for working with collections of data in Java, it’s not always the most efficient solution for every problem. In some cases, traditional loops or other constructs may be more appropriate.
The Stream API can be less efficient than traditional loops for small data sets, due to the overhead of creating and processing streams. Additionally, streams may introduce some additional complexity and overhead in certain cases, such as when working with stateful operations or complex parallelization.
However, for many common operations such as filtering, mapping, and reducing collections of data, the Stream API can be a very efficient and expressive solution. It can also make code more concise and easier to read, especially when working with complex data transformations.
In summary, while the Stream API can be a powerful tool for working with collections of data in Java, it’s important to consider the specific requirements of your problem and weigh the trade-offs between using streams and other approaches.