2

So I have a list and for each item in the list I have to "do something" based on each list element.

The list consists of codes and there are a total of 5 codes. The list may contain any or all codes.

So far I've used the forEach and i've written the if conditions inside it as below -

List<Category> categories = getCategories();

categories.stream().forEach(category -> {
            if(category.equals(Category.A)) {
                // do something
            } else if(category.equals(Category.B)) {
                // do something
            } else if(category.equals(Category.C)) {
                // do something
            } else if(category.equals(Category.D)) {
                // do something
            } else if(category.equals(Category.E)) {
                // do something
            }
        });

I'm looking at refactoring this. Can someone please look at how better this can be done?

  • 4
    You could put `// do something` inside a method `void doSomething()` that every Category overwrites and then simply write `category.doSomething()`. – luk2302 Nov 02 '17 at 12:57
  • 2
    Create a loopkup table. See [this question](https://stackoverflow.com/questions/4480334/how-to-call-a-method-stored-in-a-hashmap-java) for info. – pritaeas Nov 02 '17 at 12:59
  • 2
    What kind of comparison is `category.equals(Category.A)`? – Naman Nov 02 '17 at 13:29
  • @luk2302 maybe write an answer? – Lino Nov 02 '17 at 14:56
  • 1
    The stream creation is not necessary here, either. The Collection interface has a forEach method – Felix S Nov 03 '17 at 09:19

3 Answers3

1

The only thing I would improve is to use a switch-statement:

switch(category){    
   case Category.A:
        // do Something
   break;
}

As mentionend by luk2302 this will only work if Category is an enum.

Basti
  • 517
  • 4
  • 19
  • 1
    what if `Category` is simply a regular class, not an enum!? – luk2302 Nov 02 '17 at 12:59
  • Then it won't work I guess. The Author didn't really provide this info. It's worth a try. – Basti Nov 02 '17 at 13:01
  • Category is an Enum so this will work. I was going to use either the nested if or switch but the reason I asked this was to see if there was any possibility of using lambda functions to do this. –  Nov 03 '17 at 09:15
1

You can add a doSomething method to the Category class and simply call it in the .forEach.

For example:

public class Category {

    // any other methods/variable/constructors

    public void doSomething() {
        //do something
    }
}

Then you can call it like this:

categories.stream().forEach(Category::doSomething);

If the // do something has not a common behaviour, you can move the if part inside the doSomething method.

araknoid
  • 3,065
  • 5
  • 33
  • 35
  • Category is an enum. I could write the login in the enum class but I would want to keep the logic separate. This would've definitely been my implementation if it was a class. thanks! –  Nov 03 '17 at 09:19
0

At first, do not use multiline lambdas and create new method (with switch):

private void doSomethingBasedOnCategory(Category category) {
    switch(category) {
        case A: // do something
                break;
        case B: // do something
                break;
        case C: // do something
                break;
        case D: // do something
                break;
        case E: // do something
                break;
    }
}

Then use it in your lambda:

getCategories()
    .stream()
    .forEach(category -> doSomethingBasedOnCategory(category);

Another way is to create static map prefilled with keys (which will be Category.X) and values (which will be functions ready to use)

ByeBye
  • 6,650
  • 5
  • 30
  • 63