首页 > 解决方案 > 无法使用枚举过滤元素

问题描述

protected static double averagePrice( List<ComputerComponent> list ) { 
    return  list.stream()
            //  .filter( line-> EnumUtils.isValidEnum(ComputerComponentCategory.class, line.getCategory()) )    

            //  .filter( line-> isInEnum( line.getCategory(), ComputerComponentCategory.class) )    
            //   .filter( line->  inEnum(line.getCategory(),EnumUtils.getEnumMap(ComputerComponentCategory.class ).keySet() ))  
                .filter(    line -> 
                        line.getCategory().contains("CPU")  
                        || line.getCategory().contains("GPU")
                        || line.getCategory().contains("Monitor")
                        || line.getCategory().contains("Keyboard")
                        || line.getCategory().contains("Mouse")
                        || line.getCategory().contains("Storage")
                        || line.getCategory().contains("Memory")) 
               .mapToDouble(ComputerComponent::getPrice)
               .average() 
               .orElseThrow(NoSuchElementException:: new); 
    }

我有一个枚举

public enum ComputerComponentCategory {

    CPU("CPU"), 
    MONITOR("Monitor"), 
    KEYBOARD("Keyboard"), 
    MOUSE("Mouse"), 
    GPU("GPU"), 
    MEMORY("Memory"),
    STORAGE("Storage"),
    NULL("NOT DEFINED"); 

    private String label;

    ComputerComponentCategory(String label) {
        this.label = label;
    }

    public String getLabel() {
        return this.label;
    }

    public static ComputerComponentCategory getValue(String label) {

        switch(label) {
            case "CPU":
                return CPU;
            case "Monitor":
                return MONITOR;
            case "Keyboard":
                return KEYBOARD;
            case "Mouse":
                return MOUSE;
            case "GPU":
                return GPU;
            case "Memory":
                return MEMORY;
            case "Storage":
                return STORAGE;
            default: 
                return NULL ;
        }

    }
}

我将 ComputerComponent 类的列表传递给 averagePrice() 函数,该函数具有两个类型为 double 的价格字段和类型为 String 的类别。

我的列表有 4 个元素,类别为“CPU”、“鼠标”、“键盘”和“存储”,它们各自的价格分别为 34.0、155.0、23.0 和 75.0。

当我尝试使用 inEnum()、isInEnum() 或 EnumUtils.isValidEnum() 函数时,我得到的平均价格为 34.0,我认为它们只是返回第一个元素的价格而不是平均值。

But when I do filtering using 

                            .filter(    line -> 
                        line.getCategory().contains("CPU")  
                        || line.getCategory().contains("GPU")
                        || line.getCategory().contains("Monitor")
                        || line.getCategory().contains("Keyboard")
                        || line.getCategory().contains("Mouse")
                        || line.getCategory().contains("Storage")
                        || line.getCategory().contains("Memory"))

我得到正确的平均值 71.75。

我用于 isInEnum() 和 inEnum() 函数的实现如下:

public static <E extends Enum<E>> boolean isInEnum(String value, Class<E> enumClass) {
      for (E e : enumClass.getEnumConstants()) {
        if(e.name().contains(value)) { return true; }
      }
      return false;
    }


public static boolean inEnum ( String category, Set<String> value ) {   
    for(String s: value ) {
    if ( category.contains(s) ) {
        return true ;  
    }
    }
    return false ;
}

如何正确使用枚举和 Java 流来按有效类别名称过滤并获得正确的平均价格?

使用流及其功能时我犯了什么错误?

标签: java-8enumsjava-stream

解决方案


鉴于以下类别,您可以简单地使用您的ComputerCategoryValue.getValue方法并检查 null line

public class EnumTest {

    @Test
    public void testBothMethods() {
        final ComputerComponent c1 = new ComputerComponent(ComputerComponentCategory.CPU.getLabel(), 12.21);
        final ComputerComponent c2 = new ComputerComponent(ComputerComponentCategory.MEMORY.getLabel(), 23.45);
        final List<ComputerComponent> list = Arrays.asList(c1, c2);

        assertEquals(averagePriceWithFilter(list), averagePriceWithInEnum(list), 0.01);
    }

    protected static double averagePriceWithFilter(final List<ComputerComponent> list) {
        return list.stream()
                .filter(line -> line.getCategory().contains("CPU")
                        || line.getCategory().contains("GPU")
                        || line.getCategory().contains("Monitor")
                        || line.getCategory().contains("Keyboard")
                        || line.getCategory().contains("Mouse")
                        || line.getCategory().contains("Storage")
                        || line.getCategory().contains("Memory"))
                .mapToDouble(ComputerComponent::getPrice)
                .average()
                .orElseThrow(NoSuchElementException::new);
    }

    protected static double averagePriceWithInEnum(final List<ComputerComponent> list) {
        return list.stream()
                .filter(line -> ComputerComponentCategory.getValue(line.getCategory()) != null)
                .mapToDouble(ComputerComponent::getPrice)
                .average()
                .orElseThrow(NoSuchElementException::new);
    }
}

编辑:解释你的错误:

  1. EnumUtils.getEnumMap(ComputerComponentCategory.class).keySet())返回枚举名称(不是它的label)的映射,以便检查仅适用于CPU名称和标签相同的情况。

  2. 其他方法也一样!

您需要使用getLabel()代替name()或使用equalsIgnoreCase代替contains


推荐阅读