Ted Wang a master of none

Loopless Code Style (Stream)

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:


Select with filter()


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());
    }
}


Sum with mapToInt() and sum()


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();
    }
}


Nested list sum with flatMapToInt() and 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.