May 10, 2021 Java
When using Java collections, we use external iterations.
In an external iteration, we use for or for each loop, or get iterators for collections and process elements of collections in a sequence.
The following code calculates the sum of the squares of all odd integers in the list.
It uses each loop to access each element in the list, and then uses an if statement to filter odd integers.
After that, it calculates the square, and finally stores the sum of the squares and the variables.
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = 0; for (int n : numbers) { if (n % 2 == 1) { int square = n * n; sum = sum + square; } } System.out.println(sum); } }
The code above produces the following results.
We can use stream to rewrite the code above. It does exactly the same thing.
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .filter(n -> n % 2 == 1) .map(n -> n * n) .reduce(0, Integer::sum); System.out.println(sum); } }
In the code above, we didn't use loop statements to traverse List. We execute the loop internally through the flow.
For odd integer calculations, we use the lambda expression. We first did the filtering, then the mapping and then the reduction.
The code above produces the following results.
External iterations usually mean sequential code. Sequential code can only be executed by one thread.
Streams are designed to process elements in parallel.
The following code calculates the sum of the squares of the odd integers in the list in parallel.
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.parallelStream() .filter(n -> n % 2 == 1) .map(n -> n * n) .reduce(0, Integer::sum); System.out.println(sum); } }
All we're doing is replacing stream () with paralStream().
Parallel calculations are easy when using internal iterations provided by the stream.
The code above produces the following results.
In command programming, we not only control what we do, but also how we do it.
For example, when you use command programming to add integers to a list. W e have to decide how to iterate each element in the list. W e can use the for loop, the for-each loop, or we can get an Iterator object from list and use the while loop. And then we're going to do the sum.
In declarative programming, we just need to tell what to do and how that part is handled by the system itself.
Collections support command programming, while streams support declared programming.
The Streams API supports functional programming by using lambda expressions.
What we do with streaming elements is usually done by passing lambda expressions.
Actions on the stream produce results without modifying the data source.
Streams support two types of operations:
Intermediate operations are also known as lazy operations.
Terminal operations are also known as eager operations.
Lazy operations do not process elements until eager operations are called on the stream.
The intermediate operation on the stream produces another stream.
Streams link operations to create a flow pipeline.
In the following code, both filter() and map() are lazy operations. And reduce() is an urgent operation.
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.parallelStream() .filter(n -> n % 2 == 1) .map(n -> n * n) .reduce(0, Integer::sum); System.out.println(sum); } }
The code above produces the following results.