toy
toy

Reputation: 12141

Is this the correct way of doing functional programming in Java?

I'm trying to change my way of thinking to be more functional. Here's the sample code which I'm trying to change to be more functional.

 List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 6);

 ArrayList<Integer> multipledByTwo = new ArrayList<Integer>();

 for(Integer number : numbers) {
       multipledByTwo.add(number * 2);
 }

As far as I understand about functional java, the simplest rule which is no shared state. Am I correct to understand that this code there's a shared state which is multipledByTwo. Here's my version of functional java.

class MultipleByTwoIteration {
    public static List<Integer> map(List<Integer> numbers) {
        ArrayList<Integer> multipledByTwo = new ArrayList<Integer>();
        for(Integer number : numbers) {
            multipledByTwo.add(multipleByTwo(number));
        }

        return multipledByTwo;
    }

    private static Integer multipleByTwo(Integer number) {
        return number * 2;
    }
}

So I could just do

List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 6);
List<Integer> multipledByTwo = MultipleByTwoIteration.map(numbers);

Am I correct that this is more of a functional way thinking? How do I improve my code if it's not functional?

Thanks.

Upvotes: 2

Views: 132

Answers (2)

blalasaadri
blalasaadri

Reputation: 6188

I guess it is a bit more functional but not by much. Your map function is aware of the operation it will use for example; if you wanted a functional version of what you've written without using Guava or Java 8 I'd suggest something like this:

public interface Function<S, T> {
    T apply(S in);
}

abstract class MappingClass<S, T> {
    protected List<T> map(List<S> list, Function<S, T> fun) {
        List<T> result = new ArrayList<T>();
        for(T item : list) {
            result.add(fun.apply(item));
        }
    }
}

class MultipleByTwoIteration extends MappingClass {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 6);

        List<Integer> multipledByTwo = map(numbers, 
                new Function<Integer, Integer>() {
            public Integer apply(Integer in) {
                return in * 2;
            }
        });
    }
}

This is part of what's being added in Java 8 or in Guava, but manually done. The map function knows nothing about what it's doing apart from that it's doing it to every element in the list past to it. The passed function has no idea of the context in which it is being used. And therefore it can all be used in other contexts without having to modify anything except the main function.

Edit: Just FYI, in Java 8 the same will be possible like this:

class MultipleByTwoIteration extends MappingClass {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2 ,3, 4, 5, 6);

        List<Integer> multipledByTwo =
            numbers.stream().map(x -> x * 2).collect(Collectors.toList());
    }
}

The Function interface, map function and a much shorter syntax for creating anonymous functions (see the x -> x * 2 there?) among other things will be provided.

Upvotes: 1

Mark Elliot
Mark Elliot

Reputation: 77024

It's probably preferable to use Guava (or Guava-like) style to implement this. Instead of for each method having a class that knows how to iterate, you can implement a Function<From,To> interface, and then use the appropriate utility class to apply the implementation.

For your example, in Guava:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

List<Integer> multipliedByTwo = Lists.transform(numbers, new Function<Integer, Integer>(){
      @Override
      public Integer apply(Integer input) {
          return input * 2;
      }
  }

This style will likely easily translate in Java 8 to lambda functions.

There's a great article on functional idioms in Guava with additional examples and suggestions.

Upvotes: 3

Related Questions