我应该将java Stream.map函数与switch语句一起使用吗?

时间:2014-08-01 07:49:24

标签: java lambda functional-programming java-8

我想根据类型将对象流传输到不同的对象。 例如:

Stream<Animal> animals = Arrays.stream(Arrays.asList(new Animal("A"),new Animal("B")));
Stream result = animals.map(animal) ->{
    switch (animal.getType()) {
       case "A" : return new Bird(animal);
       case "B" : return new LION(animal);
       case "C" : return new Tiger(animal);
       case "D" : return new FISH(animal);  
    }
}

这是一种功能性编程“反模式”吗?

我可以通过函数式编程实现上述不同吗?

(注意:我也不喜欢每次添加新类型时我都需要更新所有的switch语句)

3 个答案:

答案 0 :(得分:5)

@TimB在其answer中是正确的。这与函数式编程无关。

正如你所说:

  

每次添加新类型时,我都必须更新所有的switch语句

你的&#34;工厂lambda&#34;打破了Open/closed principle

  

软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改

您可以创建遵循此原则的动物工厂:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;

public class AnimalFactory {
    private final Map<String, Function<Animal, Object>> delegateFactories
        = new HashMap<String, Function<Animal,Object>>();

    public AnimalFactory withFactory(String type, Function<Animal, Object> factory) {
        delegateFactories.put(type, factory);
        return this;
    }

    public Object createAnimal(Animal animal) {
        return delegateFactories.get(animal.getType()).apply(animal);
    }
}

您可以通过taking advantage of java 8 feature

轻松使用它
public static void main(String[] args) {
    Stream<Animal> animals = Arrays.asList(new Animal("A"),new Animal("B")).stream();
    AnimalFactory animalFactory = new AnimalFactory();
    animalFactory.withFactory("A", Bird::new);
    animalFactory.withFactory("B", Lion::new);
    animalFactory.withFactory("C", Tiger::new);
    animalFactory.withFactory("D", Fish::new);

    Stream result = animals.map(animalFactory::createAnimal);
}

答案 1 :(得分:4)

switch的替代方法是使用Map将值映射到封装所需行为的对象。即使这种模式存在很长时间,Java 8也为以直接的方式实现它提供了新的可能性:

// one-time initialization code
Map<String,Function<Animal,Animal>> factories=new HashMap<>();
factories.put("A", Bird::new);
factories.put("B", Lion::new);
factories.put("C", Tiger::new);
factories.put("D", Fish::new);

// use case
Stream<Animal> animals = Stream.of(new Animal("A"),new Animal("B"));
Stream result = animals.map(a -> factories.get(a.getType()).apply(a));

答案 2 :(得分:2)

你是对的,这种转换几乎总是一种反模式,尽管它实际上与流媒体没有关联。

解决此问题的最简单方法是使用工厂。你没有做新的Bird,而是做了:

Animals.createAnimal(animal);

并且该工厂方法返回正确的类型。

您可能仍需要在工厂内部进行切换,但至少将其封装在一起并且仅在代码中的一个位置。