2

After learning about lambdas in Java 8, I have been trying to think more functionally.

For example, in this algorithm I loop through an array to see which GraphicsDevice in the array matches the GraphicsDevice that is currently in use. It sets a value of the non-matching elements to false, and a value of the matching element to true.

How would I express this functionally? Or, are some things better expressed proceduraly? The method I came up with 1) doesn't work because forEach returns void, and even if it did work, it feels unnatural compared to the enhanced for loop being used in my "procedural version" of the algorithm.

public void findCurrentMonitor() {

    GraphicsDevice current = frame.getGraphicsConfiguration().getDevice();

    // Procedural version
    for (Monitor m : monitors)
        if (m.getDevice() == current) m.setCurrent(true);
        else m.setCurrent(false);

    // Functional version
    monitors.stream()
    //  .forEach(a -> a.setCurrent(false)) # Impossible. Returns void.
        .filter (a -> a.getDevice() == current)
        .forEach(a -> a.setCurrent(true));
}
Connorelsea
  • 2,308
  • 6
  • 26
  • 47
  • 2
    Why not `monitors.stream().forEach(a -> a.setCurrent(a.getDevice() == current))`? Is this a dummy example and are you asking for the general approach with `if-else` in a loop? – Vincent van der Weele Feb 16 '15 at 07:09
  • This is not a dummy example. It is an example pulled from a small screenshot utility program I am making. And your answer works, though to me there is something not so elegant about it, or the code I have for that matter. If you post it as an answer I will accept it, though I am still wondering if it would just be better to leave it procedural. – Connorelsea Feb 16 '15 at 07:13

1 Answers1

3

Well from pure functional programming perspective, Monitor should be immutable. You could do something like:

Stream<Monitor> stream = monitors.stream().map(x -> new Monitor(m.getDevice(), m.getDevice()==current));

In case, you wish to mutate the same monitors, why not just:

monitors.stream().forEach(a -> a.setCurrent(a.getDevice() == current));
Jatin
  • 31,116
  • 15
  • 98
  • 163
  • In this case, is it better to go with a purely functional design? What benefits do I get from making Monitor immutable and going to the extra trouble? Should the purely functional design be implemented in my program, or is it a waste of time? – Connorelsea Feb 16 '15 at 07:14
  • 1
    @Connorelsea it completely depends on your use case. Why go immutability is a topic on its own (a google search would give many many superb links). I prefer immutability when to be rest assured that the state cant be changed and I can pass around the objects stress-free. Especially when there is concurrency involved. In your case, when in the code-design the mutation is acceptable and coded accordingly. I would prefer the second one as its less verbose. – Jatin Feb 16 '15 at 07:18
  • To me, changing a Monitors state from current or not current makes sense, and seems less computationally intensive than creating a new Monitor object every time you want to change its state. I've never really understood the whole "immutability is better for everything stance," because of exactly what I said in my first sentence. Changing a monitor's state from current to not-current seems logical and easy to understand. Am I missing something? – Connorelsea Feb 16 '15 at 07:40
  • 1
    @Connorelsea Firstly creating a new object is cheap. very much in most circumstances. But program where the object state can be changed anytime by anyone and the effort required to make sure the conditional flow still works accurately after the state is changed - is expensive. Suppose you have a class `Point` with x,y variables. Suppose you have initialized with values `(1,1)`. If point is immutable, you can safely pass point object to any method and be rest-assured the value wont change. ur code can function as if it will be (1,1) forever. – Jatin Feb 16 '15 at 07:47
  • 1
    But if it could be changed, then u need to check again and take extra effort to see if the value has changed. if so then perform other set of operations. All this effort to stress if the value has changed is too much load. Knowing it would never change is a very big reliever. Especially if multiple threads were using the same point object. Any decent book/link on functional programming will have many more better insights on why immutability is reallly awesome. The only place i think it is bad, is where performance is necessary at a very very micro level – Jatin Feb 16 '15 at 07:47
  • I will have to read up on it. I will look around the web, because to me just changing a boolean seems so natural. For example, with a lightswitch. If I turn it off, it's state changes to off, it doesn't create a new off lightswitch and replace the on lightswitch. It's just odd to me. – Connorelsea Feb 16 '15 at 07:51
  • And I just noticed that in your purely functional example, you are basically re-creating the entire array every time you want to change ONE value in the array. I know with an array of "monitors" it will be small, but, in theory, if someone had a few hundred monitors, this would have to be a bad way to do it... – Connorelsea Feb 16 '15 at 08:02
  • 1
    @Connorelsea For your lightbulb example. if its a simple example, then probably changing the state is the easier go. But in case its a large program then it becomes a pain. What if multiple threads are working on same light bulb. You have to synchronize it properly, keep checking the state if it has not changed and take subsequent action. Or what if multiple objects rely on state of light bulb? It keeps getting complex. – Jatin Feb 16 '15 at 08:19
  • 1
    @Connorelsea An example would be String. Strings in java are immutable. Say in a class you had `public static final String version = "1.0"`. In ur program when ever u use `version`, u are rest assured the value is always `1.0`. So you are executing a block `if(s.equals(version)){doA()} else {doB()}` and you start executing `doA`. What if String was mutable and then someone changed the value of version to `2.0` while you were executing `doA`. The program is in an inconsistent state as value should not be changed till doA is over. Though the problem can be, but it is so much effort & complexity – Jatin Feb 16 '15 at 08:26
  • 1
    Some good reads: http://stackoverflow.com/questions/3769607/why-do-we-need-immutable-class – Jatin Feb 16 '15 at 08:32