包含函数的java枚举-使用开关或供应商作为成员变量

包含函数的java枚举-使用开关或供应商作为成员变量,java,lambda,enums,java-8,switch-statement,Java,Lambda,Enums,Java 8,Switch Statement,我想要一个枚举,它提供一个包含新类构造函数的函数。在Java8之前,我常常编写以下代码: enum Fruit1 { APPLE, BANANA; public Tree getTree() { switch (this) { case APPLE: return new AppleTree(); case BANANA: return new Ban

我想要一个枚举,它提供一个包含新类构造函数的函数。在Java8之前,我常常编写以下代码:

enum Fruit1 {
    APPLE, BANANA;

    public Tree getTree() {
        switch (this) {
            case APPLE:
                return new AppleTree();
            case BANANA:
                return new BananaTree();
            default:
                throw new IllegalStateException();
        }
    }
}
现在,我可以使用lambda表达式。优点是,在添加新的枚举项时,不能忘记向switch语句中添加sth。但是我不喜欢代码看起来更复杂

enum Fruit2 {
    APPLE(AppleTree::new), BANANA(BananaTree::new);

    Supplier<Tree> treeSupplier;

    Fruit2(Supplier<Tree> treeSupplier) {
        this.treeSupplier = treeSupplier;
    }

    public Tree getTree() {
        return treeSupplier.get();
    }
}
enum.2{
苹果(苹果树::新),香蕉(香蕉树::新);
供应商树供应商;
结果2(供应商树供应商){
this.treeSupplier=树供应商;
}
公共树getTree(){
返回树supplier.get();
}
}
这仅仅是一个品味的问题,还是还有更多?我能用lambda表达式更好地表达吗


这与密切相关,但在这里,我想重点讨论switch表达式,与lambda表达式相比,我仍然非常熟悉它。

您的第二个代码片段看起来不错。如果您不这么认为,可以通过将方法的实现置于枚举常量级别来执行类似的操作:

enum Fruit1 {
  APPLE {
    public Tree getTree() { return new AppleTree(); }
  }, BANANA {
    public Tree getTree() { return new BananaTree(); }
 };

  public abstract Tree getTree();
}

您的第二个代码片段看起来不错。如果您不这么认为,可以通过将方法的实现置于枚举常量级别来执行类似的操作:

enum Fruit1 {
  APPLE {
    public Tree getTree() { return new AppleTree(); }
  }, BANANA {
    public Tree getTree() { return new BananaTree(); }
 };

  public abstract Tree getTree();
}

您应该问问自己,在
水果
枚举和
类层次结构之间进行如此紧密的耦合是否是一个好主意。考虑另一种选择:

public enum Fruit { APPLE, BANANA }

public class TreeFactory {
    static EnumMap<Fruit,Supplier<Tree>> SUPPLIERS=new EnumMap<>(Fruit.class);
    static {
        SUPPLIERS.put(Fruit.APPLE,  AppleTree::new);
        SUPPLIERS.put(Fruit.BANANA, BananaTree::new);
        assert SUPPLIERS.keySet().containsAll(EnumSet.allOf(Fruit.class));
    }
    public static Tree getTree(Fruit f) {
        return SUPPLIERS.getOrDefault(
            Objects.requireNonNull(f), ()->{throw new AssertionError();}).get();
    }
}
公共枚举水果{苹果、香蕉}
公共类树结构{
静态EnumMap供应商=新EnumMap(Fruit.class);
静止的{
供应商。放置(水果、苹果、苹果树::新);
供应商。放置(水果、香蕉、香蕉树::新);
断言SUPPLIERS.keySet().containsAll(EnumSet.allOf(Fruit.class));
}
公共静态树getTree(水果f){
return SUPPLIERS.getOrDefault(
Objects.requireNonNull(f),()->{throw new AssertionError();}).get();
}
}

enum
专门的集合与硬编码的替代方案一样有效,例如
switch
语句或将数据存储在
enum
常量中。但是这个解决方案可以在
水果
类型不需要了解
类型的情况下工作。

您应该问问自己,在
水果
枚举和
类层次结构之间进行如此紧密的耦合是否是一个好主意。考虑另一种选择:

public enum Fruit { APPLE, BANANA }

public class TreeFactory {
    static EnumMap<Fruit,Supplier<Tree>> SUPPLIERS=new EnumMap<>(Fruit.class);
    static {
        SUPPLIERS.put(Fruit.APPLE,  AppleTree::new);
        SUPPLIERS.put(Fruit.BANANA, BananaTree::new);
        assert SUPPLIERS.keySet().containsAll(EnumSet.allOf(Fruit.class));
    }
    public static Tree getTree(Fruit f) {
        return SUPPLIERS.getOrDefault(
            Objects.requireNonNull(f), ()->{throw new AssertionError();}).get();
    }
}
公共枚举水果{苹果、香蕉}
公共类树结构{
静态EnumMap供应商=新EnumMap(Fruit.class);
静止的{
供应商。放置(水果、苹果、苹果树::新);
供应商。放置(水果、香蕉、香蕉树::新);
断言SUPPLIERS.keySet().containsAll(EnumSet.allOf(Fruit.class));
}
公共静态树getTree(水果f){
return SUPPLIERS.getOrDefault(
Objects.requireNonNull(f),()->{throw new AssertionError();}).get();
}
}

enum
专门的集合与硬编码的替代方案一样有效,例如
switch
语句或将数据存储在
enum
常量中。但是这个解决方案不需要
水果
类型了解
类型。

如果代码看起来更复杂,为什么要使用它?我觉得它更简单、更好。但是定义你认为更好的。lambda表达式变体的可能副本不含条件句,但是,当然,热点优化器应该能够优化<代码>开关语句变体到类似的结果,如果它与性能相关的话。然后,唯一的区别是需要编写
default:throw new IllegalStateException()switch
语句中编写>以使编译器满意。lambda变体不需要这些……如果代码看起来更复杂,为什么要使用它?我觉得它更简单、更好。但是定义你认为更好的。lambda表达式变体的可能副本不含条件句,但是,当然,热点优化器应该能够优化<代码>开关语句变体到类似的结果,如果它与性能相关的话。然后,唯一的区别是需要编写
default:throw new IllegalStateException()switch
语句中编写>以使编译器满意。lambda变体不需要这样做……这是一个很好的解决方案——我发现,经常使用函数而不是函数类型,这两种方法都可以选择。有了这个解决方案,如果您仍然需要一个供应商,您可以使用方法引用创建一个供应商,比如
myFruit::getTree
APPLE::getTree
。这是一个很好的解决方案——我发现,经常使用函数而不是函数类型可以让您选择这两种方法。使用此解决方案,如果您仍然需要一个供应商,您可以使用方法引用创建一个供应商,如
myFruit::getTree
APPLE::getTree
。非常感谢,我喜欢fruit和tree的解耦以及对供应商的断言检查。非常感谢,我喜欢水果和树木的分离,以及对供应商的断言检查。