Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between traditional imperative style of programming and functional style of programming

I have a problem statement here what I need to do it iterate over a list find the first integer which is greater than 3 and is even then just double it and return it.

These are some methods to check how many operations are getting performed

public static boolean isGreaterThan3(int number){
        System.out.println("WhyFunctional.isGreaterThan3 " + number);
        return number > 3;
    }
    public static boolean isEven(int number){
        System.out.println("WhyFunctional.isEven " + number);
        return number % 2 == 0;
    }
    public static int doubleIt(int number){
        System.out.println("WhyFunctional.doubleIt " + number);
        return number << 1;
    }

with java 8 streams I could do it like

List<Integer> integerList = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);
integerList.stream()
           .filter(WhyFunctional::isGreaterThan3)
           .filter(WhyFunctional::isEven)
           .map(WhyFunctional::doubleIt)
           .findFirst();

and the output is

WhyFunctional.isGreaterThan3 1
WhyFunctional.isGreaterThan3 2
WhyFunctional.isGreaterThan3 3
WhyFunctional.isGreaterThan3 5
WhyFunctional.isEven 5
WhyFunctional.isGreaterThan3 4
WhyFunctional.isEven 4
WhyFunctional.doubleIt 4
Optional[8]

so total 8 operations.

And with imperative style or before java8 I could code it like

for (Integer integer : integerList) {
            if(isGreaterThan3(integer)){
                if(isEven(integer)){
                    System.out.println(doubleIt(integer));
                    break;
                }
            }
        }

and the output is

WhyFunctional.isGreaterThan3 1
WhyFunctional.isGreaterThan3 2
WhyFunctional.isGreaterThan3 3
WhyFunctional.isGreaterThan3 5
WhyFunctional.isEven 5
WhyFunctional.isGreaterThan3 4
WhyFunctional.isEven 4
WhyFunctional.doubleIt 4
8

and operations are same. So my question is what difference does it make if I am using streams rather traditional for loop.

like image 767
eatSleepCode Avatar asked Dec 02 '22 14:12

eatSleepCode


1 Answers

Stream API introduces the new idea of streams which allows you to decouple the task in a new way. For example, based on your task it's possible that you want to do different things with the doubled even numbers greater than three. In some place you want to find the first one, in other place you need 10 such numbers, in third place you want to apply more filtering. You can encapsulate the algorithm of finding such numbers like this:

static IntStream numbers() {
    return IntStream.range(1, Integer.MAX_VALUE)
                    .filter(WhyFunctional::isGreaterThan3)
                    .filter(WhyFunctional::isEven)
                    .map(WhyFunctional::doubleIt);
}

Here it is. You've just created an algorithm to generate such numbers (without generating them) and you don't care how they will be used. One user might call:

int num = numbers().findFirst().get();

Other user might need to get 10 such numbers:

int[] tenNumbers = numbers().limit(10).toArray();

Third user might want to find the first matching number which is also divisible by 7:

int result = numbers().filter(n -> n % 7 == 0).findFirst().get();

It would be more difficult to encapsulate the algorithm in traditional imperative style.

In general the Stream API is not about the performance (though parallel streams may work faster than traditional solution). It's about the expressive power of your code.

like image 80
Tagir Valeev Avatar answered Dec 04 '22 03:12

Tagir Valeev