2

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.

6
  • 1
    Eh, a little, but doing "functional programming in Java" is somewhat awkward/nonsensical until Java 8 comes out. Commented Jan 12, 2014 at 21:44
  • Actually, Google Guava Lists.transform does just that. It's a Java way of map Commented Jan 12, 2014 at 21:48
  • 1
    Why don't you try a functional language instead? Commented Jan 12, 2014 at 21:49
  • 1
    Without multithreading there's no shared state. Commented Jan 12, 2014 at 21:52
  • Can you please explain a bit more on that @MarkoTopolnik? Commented Jan 12, 2014 at 21:55

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Mark, I'm aware of Guava, it's just that I'm trying to learn how to think functionally. I'm guessing my understanding is right?
Java 8: numbers.stream().map(i->2*i).collect(toList())
@toy The idea that you apply a function to every element of something vs. doing the work within a loop is on the right path.
1

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.

2 Comments

Or, if you know the numbers beforehand: IntStream numbers = IntStream.rangeClosed(1, 6); numbers.map(...)... or IntStream.iterate(1, i -> i + 2).limit(6).collect();
Whether or not that is better depends on the situation; if you would start with creating that exact same List then yes, an IntStream created as suggested by you would be better. If you want to do stuff with it beforehand, probably not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.