foreach() loop vs Stream foreach() vs Parallel Stream foreach() in Java
The conventional methods in Java foreach() loop give a straightforward and sequential way to iterate over collections; they are user-friendly but don't offer any efficiency enhancements. However, the forEach() method of the Streams API, which was added in Java 8, provides a more functional and expressive means of iteration, allowing for the processing of elements in a specified order in a simple manner.
An expansion of the Streams API, Parallel Streams enable concurrent processing of items, which may improve performance by utilizing many threads for big datasets or computationally demanding jobs. However, the suitableness of parallelization and possible performance overhead must be carefully considered before using them. Performance needs, parallel execution suitability, and code readability are often balanced while selecting one of these solutions.
foreach() loop:
A foreach() loop, more commonly referred to as an enhanced for loop in Java, offers a clear and understandable method of iterating over elements in an array or collection. It eliminates the need to manually maintain loop counters or indices, making it easier to iterate through every element of a collection.
1. If the Lambda operator is not used:
Since the Java foreach loop lacks the use of lambda operations, operations can be applied on any item that is not part of the list that is being iterated through. The foreach loop is responsible for iterating across a collection or array by assigning a local variable to each list element and carrying out the desired foreach() loop operations.
Implementation:
FileName: NoLambdaOperator.java
import java.io.*; import java.util.*; public class NoLambdaOperator { public static void main(String[] args) { String[] array = { "1", "2", "3", "4" }; int c = 0; String[] array1 = { "Hello", "Welcome", "To", "World" }; for (String str : array) { System.out.print(array1[c++]); } } }
Output:
HelloWelcomeToWorld
Explanation:
Since the count is inside the scope of the foreach loop, operations on it are available despite it being a variable outside the loop.
2. Applicable for all the collections and arrays:
Iterating across all Java arrays and collections is possible with it. The interfaces or standards that specify the required iteration methods are usually implemented by collections and arrays that support the foreach loop. Collections that implement the Iterable interface, for instance, can be used with foreach in Java.
Implementation:
FileName: CollectionandArrays.java
import java.io.*; import java.util.*; public class CollectionandArrays { public static void main(String[] args) { String[] array = { "1", "2", "3", "4" }; int c = 0; String[] array1 = { "Hello", "Welcome", "To", "World" }; for (String str : array) { System.out.print(array1[c++]); } } }
Output:
HelloWelcomeToWorld
3. Return statements also work within the foreach() loop:
Within the loop, the function has the ability to return the value at any period. For instance, we can use Java's foreach loop to print just the first two items of any collection or array before returning any value. Printing an array's second element is possible with the code below.
Implementation:
FileName: ReturnStmtsinLoop.java
import java.io.*; import java.util.*; public class ReturnStmtsinLoop { public static String foreach(String[] hello) { int c = 0; for (String vari : hello) { if (c == 1) return vari; c++; } return ""; } public static void main(String[] args) throws Exception { String[] array1 = { "Hello", "Welcome", "To World" }; String res = foreach(array1); System.out.println(res); } }
Output:
Welcome
stream().forEach():
A Java 8 feature called stream().forEach() allows for quick iteration over elements in a stream. It is part of the Stream API. Every stream element is subjected to a designated action, denoted by a lambda expression or method reference. By blurring the lines between the underlying loop mechanism and functional programming techniques, this approach streamlines iteration. It can be applied to a number of tasks, such as manipulating, printing, and computing elements. When utilized with parallel streams, it can also enable sequential or parallel execution, depending on the kind of stream. It improves the speed of huge datasets.
1. Lambda operator is used:
Operations on variables outside of the loop are not allowed in the stream().forEach() due to the usage of lambdas. The only possible operations are those on the relevant collections. It allows us to operate on Collections using a single line of code, which simplifies and eases coding.
Implementation:
FileName: StreamLambdaOperator.java
import java.io.*; import java.util.*; public class StreamLambdaOperator { public static void main(String[] args) throws Exception { Listarray1 = new ArrayList (); int c = 0; array1.add("Hello"); array1.add("Welcome"); array1.add("To World"); array1.stream().forEach(s -> { //It will generate an error c++; // displays all the elements System.out.print(s); }); } }
Output:
StreamLambdaOperator.java:15: error: local variables referenced from a lambda expression must be final or effectively final c++; ^ 1 error
Note:
Although lambda operations are incapable of allowing any external variable action within themselves, the operation "count++" will result in an error.
2. Only used to iterate collections:
The stream().forEach() is only used for accessing the collections like set and list. It can also be used for accessing arrays.
Implementation:
FileName: IterateCollections.java
import java.io.*; import java.util.*; public class IterateCollections { public static void main(String[] args) throws Exception { String[] array = { "Hello", "Welcome", "To World" }; array.stream().forEach(s -> { System.out.print(s); }); } }
Output:
IterateCollections.java:11: error: cannot find symbol array.stream().forEach(s -> ^ symbol: method stream() location: variable array of type String[] 1 error
Explanation:
As there is no such thing as a stream() method, the program mentioned above will throw an error.
3. Within this loop, return statements are not functional; however, calling the function calls is very simple:
Inside the loop, the return statement is invalid. We cannot utilize the same forEach() method to carry out the identical task of getting the second element.
Implementation:
FileName: StreamReturnStmts.java
import java.io.*; import java.util.*; public class StreamReturnStmts { static String second(Listlist) { list.stream().forEach( s -> { // The subsequent line will raise an error // because there can be no return. // if(s=="For")return s; }); return "null"; } public static void main(String[] args) throws Exception { List array = new ArrayList (); array.add("Hello"); array.add("Welcome"); array.add("To World"); String res = second(array); System.out.println(res); } }
Output:
null
parallel foreach()
Sequentially iterating over stream elements is possible with Java's Stream APIs for forEach function. When used in association with the parallel() method, it allows for parallel processing, in which the stream is split up into many pieces and handled concurrently by several threads. By taking advantage of multi-core computers, this may enhance speed for huge datasets; however, thread safety and possible performance overhead from thread synchronization must be carefully considered.
1. Works on multithreading concept:
The multithreading functionality provided by the parallel forEach() is the only distinction between stream().forEach() and parallel foreach(). Compared to stream.forEach() and foreach(), this is significantly faster. The lambda symbol is also used to perform functions, just like in stream().forEach(). The following is an example that demonstrates its multithreading nature. It is quite clear that because parallelStream is multithreaded, the output will never print the strings in the same order.
Implementation:
FileName: ParllelForeachStream.java
import java.util.*; import java.io.*; public class ParllelForeachStream { public static void main(String[] args) throws Exception { Listarray = new ArrayList (); array.add("Hello"); array.add("Welcome"); array.add("To World"); array.parallelStream() .forEach(s -> { System.out.print(s); }); } }
Output:
WelcomeTo WorldHello
Differences between the foreach() loop; Stream foreach(); Parallel Stream foreach()
foreach() loop | streamforeach() Loop | ParallelStream()foreach() |
No Lambda Operators are used. | Lambda Operators are used. | Lambda Operators are used. |
It can be used to retrieve collections and arrays. | It can be used to retrieve collections only. | It can be used to retrieve collections only. |
Within the loop, the control or return statements are functional. | Within the loop, the control or return statements are non-functional. | Within the loop, the control or return statements are non-functional. |
Slow data is in sequence since there is no multithreading. | Slow data is in sequence since there is no multithreading. | It runs quickly because it is multithreaded, and the order is distinct. |