5

I have the following problem regarding the correct use of streams and map.

The problem is the following

I have a method that reads a file from input and inserts record in a database, in a few words it performs some side effects

Furthermore, the same function returns some sort of a state, let's say a boolean (I have some degree of freedom about this) that states that the function went well.

public static boolean execute(String filename){

    // Perform some side effects (e.g. write on DB)

    return true; // or false according to some criteria;

}

Then, I have to call it with let's say two files and I have to detect if at least one went well (i.e. if at least one execution returned true)

My simple solution is: (a sort of simplified version of the command pattern)

public class Entrypoint {

    public static boolean myFunction(String input) {
        System.out.println("executed..." + input);
        return !input.equals("B");
    }

    public static void main(String[] args) {

        List<String> lst = Arrays.asList("A", "B", "C", "D", "E", "F");

        long callsOk = lst.stream().map(Entrypoint::myFunction)
            // .filter(x -> x.equals(true)).count();
            .filter(x -> x).count(); // Better, as suggested by Donat

        System.out.println("OK=" + callsOk);

    }
}

This work, fine, the output is:

executed...A
executed...B
executed...C
executed...D
executed...E
executed...F
OK=5

That is right because it should fail (return false) for "B"

The question is:

Is it fine to use a function like myFunction:

  • whose prime purpose is to perform side effects

and

  • the purpose of its return value is just to give the status of the operation performed (success or not) and no other kind of data

inside a map in order to count the number of yields == true?

Or am I messing up, and there is a better solution to handle this?

Ettore Galli
  • 677
  • 6
  • 24
  • For the awareness - [Java8 Vs Java9 behavior](https://stackoverflow.com/questions/48221783/stream-peek-method-in-java-8-vs-java-9). – Naman Aug 19 '20 at 00:48

1 Answers1

2

There are two answers.

First: Yes, it works. You can do it like this.

Second: Do not do this! Streams are for functional programming and functional programming is about avoiding side effects. This is kind of a misuse and it can be confusing. Think about more complicated cases! Someone familiar with functional programming will probably not expect this misuse.

This means: You should not use streams if you have imperative code with side effects or stateful operations. In this case a classical for each loop is the better choice. This is a matter of style. In many cases (like this one) the solution with streams is working well, but it is bad style.

Another issue: When you avoid side effects in streams, you can easily change them to parallel execution.

By the way, filter(x -> x.equals(true)) can be simplified to filter(x -> x).

Donat
  • 4,157
  • 3
  • 11
  • 26
  • Is there a "right"/"suggested" way to achieve my goal? (i.e. execute the functions and count the number of results == true) – Ettore Galli Aug 18 '20 at 21:06
  • 1
    I would suggest to do it in a for each loop. – Donat Aug 18 '20 at 21:49
  • 1
    @Donat: How executing code in a for loop, rather than using streams, make a difference here? I somehow miss the point here. can you please elaborate ? – Sahil Gupta Aug 19 '20 at 10:55
  • @Sahil Gupta: Both solutions (stream and for each) are working correctly in this case. It is a matter of style which one to use. Please ask a more specific question, if you still do not understand. I will try to answer. – Donat Aug 19 '20 at 14:36