Loops are annoying to write, especially when you write them for a living… If you are tired of writing a full loop like me, you can maybe take a loop at Streams. Stream is a very effective way of reducing code lines and make your code look pretty. Here are some example of it, and you should get what I mean:
public class Demo {
/**
* You have a ArrayList as follow:
* list = [1,2,3,1,4,2,3,5]
*
* You want to find all numbers that are divisible by 2 and return them as a list. How could you do it?
* Intuitively, you would probably do this:
*/
public List<Integer> getDivisibleList(List<Integer> list) {
List<Integer> divisibleList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i) % 2 == 0) {
divisibleList.add(list.get(i));
}
}
return divisibleList;
}
/**
* The above solution is probably what you leaned in school. It does work, but here is how we do it:
*/
public List<Integer> getDivisibleListNoLoop(List<Integer> list) {
return list.stream().filter(integer -> integer % 2 == 0).collect(Collectors.toList());
}
}
Now do you believe me? Still not convinced? Here’s a more complex example.
public class Demo {
/**
* Now we want to get the sum of all numbers in this list:
* list = [1,2,3,1,4,2,3,5]
*
* Again, you problably would do this:
*/
public int getListSum(List<Integer> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
return sum;
}
/**
* Here is how we would do it:
*/
public int getListSumNoLoop(List<Integer> list) {
return list.stream().mapToInt(Integer::intValue).sum();
}
}
Quite interesting eh? But you might still have doubts. What if things are even more complicated? Let’s see another example.
public class Demo {
/**
* Now, we have a nested loop of integers, and we want to get the sum of all of them.
* list = [[1,3,2],[1,6],[1,2,3,4]]
*
* Well, you probably would do it with nested loops:
*/
public int getNestedListSum(List<List<Integer>> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.get(i).size(); j++) {
sum += list.get(i).get(j);
}
}
return sum;
}
/**
* The solution above already looks pretty convoluted. How does my team would solve it? Like this:
*/
public int getNestedListSumNoLoop(List<List<Integer>> list) {
return list.stream().flatMapToInt(integers -> integers.stream().mapToInt(Integer::intValue)).sum();
}
}
You might start to notice that all the problems presented above are solved in one line without using loop
of if/else
statement.
I think you are now convinced that loops
are not mandatory in codes. In fact, they actually make the codes look quite convoluted
and unnecessarily tedious. stream
is getting more popular in today’s code writing. There are a lot more functionalities and
use case than the few I have showed above. You can get the maximum with just .stream().max()
, find match element with
stream().anyMatch()
or stream().allMatch()
, conditioning in stream with stream().takeWhile()
and stream().dropWhile()
, and
etc… There are so much you can do with stream
and code looks much cleaner, and once you get used to it, the readability actually
improved from all the loops
and if/else
statements.
Of course, this is by no mean saying that stream
is always better than loop
. Sometimes loops
are easier and cleaner compared to
stream
. It is your choice. You are the god that creates your code after all. But my point is, code style does matter, and we
should keep them clean.
Codes are easy to write, and easy to make them work, but hard to keep a clean style. This is the distinction between a workable piece of code and a well-styled art.
Written on September 19th, 2020 by Ted Wang