枚举类常见用法(A Guide to Java Enums)


Java 5 引入枚举类, 详情可参考 官方文档.

一言以蔽之,啥是枚举类

纯枚举值

public enum PizzaStatus {
    
    
    ORDERED,
    READY, 
    DELIVERED; 
}

枚举值添加属性

public enum Distance {
    
    
    KILOMETER("km", 1000), 
    MILE("miles", 1609.34),
    METER("meters", 1), 
    INCH("inches", 0.0254),
    CENTIMETER("cm", 0.01), 
    MILLIMETER("mm", 0.001);

    private String unit;
    private final double meters;

    private Distance(String unit, double meters) {
    
    
        this.unit = unit;
        this.meters = meters;
    }

    // standard getters and setters
}

Fields, Methods and Constructors in Enums(枚举值还可以提供方法)

@Data
public class Pizza {
    
    
    public enum PizzaStatus {
    
    
        ORDERED(5) {
    
    
            @Override
            public boolean isOrdered() {
    
    
                return true;
            }
        }, READY(2) {
    
    
            @Override
            public boolean isReady() {
    
    
                return true;
            }
        }, DELIVERED(0) {
    
    
            @Override
            public boolean isDelivered() {
    
    
                return true;
            }
        };

        private int timeToDelivery;

        PizzaStatus(int timeToDelivery) {
    
    
            this.timeToDelivery = timeToDelivery;
        }

        // 下单
        public boolean isOrdered() {
    
    
            return false;
        }

        // 准备
        public boolean isReady() {
    
    
            return false;
        }

        // 交付
        public boolean isDelivered() {
    
    
            return false;
        }

        public int getTimeToDelivery() {
    
    
            return timeToDelivery;
        }
    }

    private PizzaStatus status;

    public boolean isDeliverable() {
    
    
        return this.status.isReady();
    }

    public void printTimeToDeliver() {
    
    
        System.out.println("Time to delivery is " + this.getStatus().getTimeToDelivery());
    }
}

Strategy Pattern(基于枚举值可以提供方法,这里可以拓展策略设计模式)

public enum PizzaDeliveryStrategy {
    
    
    EXPRESS {
    
    
        @Override
        public void deliver(Pizza pz) {
    
    
            System.out.println("Pizza will be delivered in express mode");
        }
    }, NORMAL {
    
    
        @Override
        public void deliver(Pizza pz) {
    
    
            System.out.println("Pizza will be delivered in normal mode");
        }
    };
    public abstract void deliver(Pizza pz);
}
    public static void main(String[] args) {
    
    
        Pizza testPz = new Pizza();
        testPz.setStatus(Pizza.PizzaStatus.READY); // true
        testPz.printTimeToDeliver(); // Time to delivery is 2
    }

Custom Enum Methods(告诉我们枚举类可以在类内部使用,上文已经见到)

@Data
public class Pizza {
    
    
    private PizzaStatus status;
    public enum PizzaStatus {
    
    
        ORDERED,
        READY,
        DELIVERED;
    }

    public boolean isDeliverable() {
    
    
        if (getStatus() == PizzaStatus.READY) {
    
    
            return true;
        }
        return false;
    }
}

Using Enum Types in Switch Statements(switch+enum组合经典用法)

public int getDeliveryTimeInDays() {
    
    
    switch (status) {
    
    
        case ORDERED: return 5;
        case READY: return 2;
        case DELIVERED: return 0;
    }
    return 0;
}

Comparing Enum Types Using “==” Operator(枚举类比较用==

the “==” operator provides compile-time and run-time safety.

run-time safety

if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED));null 会报 NullPointerException

if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED);Either value can be null and we won't get a NullPointerException

compile-time safety

PizzaStatus.DELIVERED.equals(PizzaStatus2.ORDERED)    ← 编译不会报错,会返回false

PizzaStatus.DELIVERED == PizzaStatus2.ORDERED    ← 编译会报错

如何判断一个枚举值是否存在

如何判断一个枚举值是否存在(Check if an Enum Value Exists in Java)

Singleton Pattern

public enum PizzaDeliverySystemConfiguration {
    
    
    INSTANCE;
    
    PizzaDeliverySystemConfiguration() {
    
    
        // Initialization configuration which involves overriding defaults like delivery strategy
        // 初始化配置,包括覆盖默认值,如交付策略
    }
    
    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
    
    public static PizzaDeliverySystemConfiguration getInstance() {
    
    
        return INSTANCE;
    }
    
    public PizzaDeliveryStrategy getDeliveryStrategy() {
    
    
        return deliveryStrategy;
    }
}

Pizza 类里追加如下方法

public void deliver() {
    
    
    if (isDeliverable()) {
    
    
        PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy().deliver(this);
        this.setStatus(PizzaStatus.DELIVERED);
    }
}
public static void main(String[] args) {
    
    
    Pizza pz = new Pizza();
    pz.setStatus(Pizza.PizzaStatus.READY);
    pz.deliver(); // Pizza will be delivered in normal mode 
    System.out.println(pz.getStatus() == Pizza.PizzaStatus.DELIVERED); // true
}

EnumSet

与HashSet相比更高效

@Data
public class Pizza {
    
    
    private static EnumSet<PizzaStatus> undeliveredPizzaStatuses = EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);

    private PizzaStatus status;

    public enum PizzaStatus {
    
    
        ORDERED(5) {
    
    
            @Override
            public boolean isOrdered() {
    
    
                return true;
            }
        }, READY(2) {
    
    
            @Override
            public boolean isReady() {
    
    
                return true;
            }
        }, DELIVERED(0) {
    
    
            @Override
            public boolean isDelivered() {
    
    
                return true;
            }
        };

        private int timeToDelivery;

        PizzaStatus(int timeToDelivery) {
    
    
            this.timeToDelivery = timeToDelivery;
        }

        // 下单
        public boolean isOrdered() {
    
    
            return false;
        }

        // 准备
        public boolean isReady() {
    
    
            return false;
        }

        // 交付
        public boolean isDelivered() {
    
    
            return false;
        }

        public int getTimeToDelivery() {
    
    
            return timeToDelivery;
        }
    }

    public boolean isDeliverable() {
    
    
        return this.status.isReady();
    }

    public void printTimeToDeliver() {
    
    
        System.out.println("Time to delivery is " + this.getStatus().getTimeToDelivery() + " days");
    }

    public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
    
    
        return input.stream().filter((s) -> undeliveredPizzaStatuses.contains(s.getStatus())).collect(Collectors.toList());
    }
}
public static void main(String[] args) {
    
    
    List<Pizza> pzList = new ArrayList<>();
    Pizza pz1 = new Pizza();
    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
    Pizza pz2 = new Pizza();
    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
    Pizza pz3 = new Pizza();
    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
    Pizza pz4 = new Pizza();
    pz4.setStatus(Pizza.PizzaStatus.READY);
    pzList.add(pz1);
    pzList.add(pz2);
    pzList.add(pz3);
    pzList.add(pz4);
    
    List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
    System.out.println(undeliveredPzs.size()); // 3
}

EnumMap

EnumMap与对应的HashMap相比,它是一个高效而紧凑的实现,内部表示为数组。
EnumMap(A Guide to EnumMap)

public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus(List<Pizza> pizzaList) {
    
    
    EnumMap<PizzaStatus, List<Pizza>> pzByStatus = new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class);
    for (Pizza pz : pizzaList) {
    
    
        PizzaStatus status = pz.getStatus();
        if (pzByStatus.containsKey(status)) {
    
    
            pzByStatus.get(status).add(pz);
        } else {
    
    
            List<Pizza> newPzList = new ArrayList<Pizza>();
            newPzList.add(pz);
            pzByStatus.put(status, newPzList);
        }
    }
    return pzByStatus;
}

Java 8 and Enums

public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
    
    
    return input.stream().filter((s) -> undeliveredPizzaStatuses.contains(s.getStatus())).collect(Collectors.toList());
}
public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus2(List<Pizza> pzList) {
    
    
    EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().filter(a -> a != null && a.getStatus() != null).collect(Collectors.groupingBy(Pizza::getStatus, () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
    return map;
}
public static Map<PizzaStatus, List<Pizza>> groupPizzaByStatus3(List<Pizza> pizzaList) {
    
    
    Map<PizzaStatus, List<Pizza>> collect = pizzaList.stream().filter(a -> a != null && a.getStatus() != null).collect(Collectors.groupingBy(Pizza::getStatus));
    return collect;
}
public static void main(String[] args) {
    
    
    List<Pizza> pzList = new ArrayList<>();
    Pizza pz1 = new Pizza();
    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
    Pizza pz2 = new Pizza();
    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
    Pizza pz3 = new Pizza();
    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
    Pizza pz4 = new Pizza();
    pz4.setStatus(Pizza.PizzaStatus.READY);
    pzList.add(pz1);
    pzList.add(pz2);
    pzList.add(pz3);
    pzList.add(pz4);
    
    EnumMap<Pizza.PizzaStatus, List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
    System.out.println(map);
    //{ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], READY=[Pizza(status=READY)], DELIVERED=[Pizza(status=DELIVERED)]}
    
    EnumMap<Pizza.PizzaStatus, List<Pizza>> map2 = Pizza.groupPizzaByStatus2(pzList);
    System.out.println(map2);
    // {ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], READY=[Pizza(status=READY)], DELIVERED=[Pizza(status=DELIVERED)]}
    
    Map<Pizza.PizzaStatus, List<Pizza>> map3 = Pizza.groupPizzaByStatus3(pzList);
    System.out.println(map3);
    // {READY=[Pizza(status=READY)], ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], DELIVERED=[Pizza(status=DELIVERED)]}
}

JSON Representation of Enum

Further Reading枚举类使用Jackson进行序列化与反序列化(How To Serialize and Deserialize Enums with Jackson)

@Data
public class Pizza {
    
    
    private PizzaStatus status;

    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    public enum PizzaStatus {
    
    
        ORDERED(5) {
    
    
            @Override
            public boolean isOrdered() {
    
    
                return true;
            }
        }, READY(2) {
    
    
            @Override
            public boolean isReady() {
    
    
                return true;
            }
        }, DELIVERED(0) {
    
    
            @Override
            public boolean isDelivered() {
    
    
                return true;
            }
        };

        private int timeToDelivery;

        PizzaStatus(int timeToDelivery) {
    
    
            this.timeToDelivery = timeToDelivery;
        }

        // 下单
        public boolean isOrdered() {
    
    
            return false;
        }

        // 准备
        public boolean isReady() {
    
    
            return false;
        }

        // 交付
        public boolean isDelivered() {
    
    
            return false;
        }

        @JsonProperty("timeToDelivery")
        public int getTimeToDelivery() {
    
    
            return timeToDelivery;
        }
    }

    public boolean isDeliverable() {
    
    
        return this.status.isReady();
    }
}
Pizza pz = new Pizza();
pz.setStatus(Pizza.PizzaStatus.READY);

ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(pz);
System.out.println(s);
{
    
    
  "status" : {
    
    
    "ready" : true,
    "ordered" : false,
    "delivered" : false,
    "timeToDelivery" : 2
  },
  "deliverable" : true
}

继承在枚举类中的应用

Further Reading继承在枚举类中的应用(Extending Enums in Java)

-----------------------------------------------------------------------------读书笔记摘自 文章:A Guide to Java Enums
-----------------------------------------------------------------------------读书笔记摘自 文章:Enum in Java

总结:

  • enum为关键字

  • 枚举类不支持继承

  • Enum可以实现接口

  • 枚举构造函数总是私有的。不能使用new操作符创建enum的实例

  • 枚举常量是隐式 static final 的,但是它的变量仍然可以被改变。

  • 我们可以在enum中定义方法,并且enum字段也可以覆盖它们。

  • 我们可以在java枚举中声明抽象方法,然后所有枚举字段必须实现抽象方法

  • 建议枚举使用==进行比较

猜你喜欢

转载自blog.csdn.net/weixin_37646636/article/details/132048657