0

I have a function that iterates over a heavy data set, receives a callback (Google's Guava Function) and runs the callback on every item of the data set:

void processData(..., Function<Item, Void> callback) {
  ...
  for (Item item : data) {
    callback.apply(item);
  }
} 

Using this function, I would like to pass a callback that adds all items to a list or a map:

List<Item> itemList;
processData(..., new Function<Item, Void)() {
  @Override public void apply(Item item) {
    itemList.add(item);
  }
});

However, it appears I can't do that, since itemList is not final, and cannot be final by definition.

Is there a solution to this case? Or perhaps this entire pattern is wrong?

R S
  • 11,359
  • 10
  • 43
  • 50
  • Since you are using Guava, if you do want an immutable list, why not use `ImmutableList`? It implements the `List` interface as well. – fge Jan 07 '13 at 13:12
  • 2
    Functions (in theory) should not have side effect, I'd use a custom "functional interface", for example Java8-like [`Block`](http://lambdadoc.net/api/java/util/function/Block.html) desribed as _An operation upon an input object. The operation may modify that object or external state (other objects)_ instead of weird `Function`. – Grzegorz Rożniecki Jan 07 '13 at 13:44

3 Answers3

3

You seem to have a incorrect understanding of the final keyword. This statement:

final List<Item> itemList = new ArrayList<Item> ();

only means that the itemList variable can't be reassigned. It does not prevent you from modifying the object it points to and this call:

itemList.add(someItem);

is perfectly valid on a final List. What is not allowed would be to write:

itemList = someOtherItemList; //forbidden, itemList is final
assylias
  • 321,522
  • 82
  • 660
  • 783
0

You can use final if you create an instance during declaration like this :

final List<Item> itemList = new ArrayLis<Item>();
processData(..., new Function<Item, Void)() {
  @Override public void apply(Item item) {
    itemList.add(item);
  }
});

final means that you can't reassign a variable but you can call methods on it !

Jerome Cance
  • 8,103
  • 12
  • 53
  • 106
0

Since what you need is a List and input is also a List, I think Lists.transform is a choice in your case:

List<Item> itemList = Lists.transform(fromList, new Function<Item, Item>(){
    @Override public Item apply(Item input) {
        ...
        return transformedItem;
    }});
卢声远 Shengyuan Lu
  • 31,208
  • 22
  • 85
  • 130