简体   繁体   English

如何通过流中的三元条件返回值?

[英]How to return value by ternary condition in a stream?

I want to return a value of a stream based on a condition. 我想根据条件返回流的值。 Take the following as an example only, where I want to map any apple to Food.APPLE : 以下面的示例为例,我想将任何苹果映射到Food.APPLE

public enum Food {
    APPLE, APPLE2, APPLE3, BANANA, PINEAPPLE, CUCUMBER;

    private static final Food[] APPLES = new Food[] {APPLE, APPLE2, APPLE3};

    //java7
    public Food fromValue(String value) {
        for (Food type : Food.values()) {
            if (type.name().equalsIgnoreCase(value)) {
                return ArrayUtils.contains(APPLES, type) ? APPLE : type;
            }
        }
        return null;
    }

    //java8: how to include the array check for APPLES?
    public Food fromValue(String value) {
        return Arrays.stream(Food.values()).
            filter(type -> type.name().equalsIgnoreCase(value))
            .findFirst()
            .orElse(null);
    }
}

How can I include the ternary condition in a stream? 如何在流中包含三元条件?

You could do it like this: 你可以这样做:

import static java.util.AbstractMap.SimpleImmutableEntry;

...

enum Food {
    APPLE, APPLE2, APPLE3, BANANA, PINEAPPLE, CUCUMBER;

    private static final Map<String, Food> MAP = Stream.concat(
                Stream.of(APPLE, APPLE2, APPLE3).map(e -> new SimpleImmutableEntry<>(e.name().toLowerCase(), APPLE)),
                Stream.of(BANANA, PINEAPPLE, CUCUMBER).map(e -> new SimpleImmutableEntry<>(e.name().toLowerCase(), e)))
            .collect(toMap(SimpleImmutableEntry::getKey, SimpleImmutableEntry::getValue));

    public static Food fromValue(String value) {
        return MAP.get(value.toLowerCase());
    }
}

The lookup in the map will be O(1) . 地图中的查找将是O(1)

As Alexis suggested, you can use a map operation 正如Alexis建议的那样,您可以使用地图操作

public Food fromValue_v8(String value) {
    return Arrays.stream(Food.values())
        .filter(type-> type.name().equalsIgnoreCase(value))
        .map(type -> ArrayUtils.contains(APPLES, type) ? APPLE : type)
        .findFirst()
        .orElse(null);
}

There is nothing special to the ternary operator. 三元运算符没有什么特别之处。 So you can simply add this mapping operation to the Stream 因此,您只需将此映射操作添加到Stream

public Food fromValue(String value) {
    return Arrays.stream(Food.values())
        .filter(type -> type.name().equalsIgnoreCase(value))
        .map(type -> ArrayUtils.contains(APPLES, type)? APPLE: type)
        .findFirst()
        .orElse(null);
}

However, neither of these linear searches is really necessary. 但是,这些线性搜索都不是必需的。 Use a Map : 使用Map

public enum Food {
    APPLE, APPLE2, APPLE3, BANANA, PINEAPPLE, CUCUMBER;

    private static final Map<String,Food> MAP
        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    static {
       EnumSet<Food> apples=EnumSet.of(APPLE, APPLE2, APPLE3);
       apples.forEach(apple->MAP.put(apple.name(), APPLE));
       EnumSet.complementOf(apples).forEach(e->MAP.put(e.name(), e));
    }
    public static Food fromValue(String value) {
        return MAP.get(value);
    }
}

It will perform a case insensitive lookup as desired and it is initialized to return the APPLE substitute in the first place so no additional comparison is required. 它将根据需要执行不区分大小写的查找,并将其初始化为首先返回APPLE替换,因此不需要进行其他比较。

According to previous answers, in particular from @Alexis I wrote some code to check booth approach (from Java 7 and Java 8). 根据之前的答案,特别是来自@Alexis,我写了一些代码来检查booth方法(来自Java 7和Java 8)。 Maybe this can be useful for new users on Java 8. 也许这对Java 8上的新用户有用。

So, I've made some changes in original answer. 所以,我在原始答案中做了一些改动。 First of all, I put some unit test and I added two wrapping methods verifyNames() and contains() . 首先,我进行了一些单元测试,并添加了两个包装方法verifyNames()contains() Second, we can use a default behavior when unexpected action occurs, in this case, when the appleApproachTwo.fromValueJava8() was called with null or an not existing enum value. 其次,我们可以在发生意外操作时使用默认行为 ,在这种情况下,当使用null不存在的枚举值调用appleApproachTwo.fromValueJava8()时。

Finally, the last change uses the potential uses for java.util.Optional objects. 最后,最后一次更改使用了java.util.Optional对象的潜在用途。 In this case, we can protect the environment to crash due to inconsistency to null objects. 在这种情况下,我们可以保护环境因为与null对象不一致而崩溃。 There are more discussion about Default Values, Optional and orElse() method at Default Values and Actions 有关默认值和操作的默认值,可选和orElse()方法的更多讨论

    public enum Food {
    APPLE, APPLE2, APPLE3, BANANA, PINEAPPLE, CUCUMBER, NONE;

    private static final Food[] APPLES = new Food[] {APPLE, APPLE2, APPLE3};

    // approach one
    // java7: conventional use
    public Food fromValueJava7(String value) {
        for (Food type : Food.values()) {
            if (verifyNames(type, value)) {
                return contains(Food.APPLES, type) ? Food.APPLE : type;
            }
        }
        return null;
    }


    // approach two
    // java8: how to include the array check for APPLES?
    public Food fromValueJava8(String value) {
        return Arrays.stream(Food.values())
                .filter(type-> verifyNames(type, value))
                .map(type -> contains(Food.APPLES, type) ? Food.APPLE : type)
                .findFirst()
                .orElse(Food.NONE);
    }

    private boolean contains(Food[] apples, Food type) {
        return ArrayUtils.contains(apples, type);
    }

    private boolean verifyNames(Food type,String other) {
        return type.name().equalsIgnoreCase(other);
    }
    }

    //   FoodTest
    //   
    public class FoodTest {
    @Test
    public void foodTest(){
        Food appleApproachOne  = Food.APPLE;

        // from approach one
        assertEquals( appleApproachOne.fromValueJava7("APPLE"),   Food.APPLE);
        assertEquals( appleApproachOne.fromValueJava7("APPLE2"),  Food.APPLE);
        assertEquals( appleApproachOne.fromValueJava7("APPLE3"),  Food.APPLE);
        assertEquals( appleApproachOne.fromValueJava7("apple3"),  Food.APPLE);
        assertNull  ( appleApproachOne.fromValueJava7("apple4") );
        assertNull  ( appleApproachOne.fromValueJava7(null) );

        Food appleApproachTwo  = Food.APPLE;

        //from approach two
        assertEquals( appleApproachTwo.fromValueJava8("APPLE"),   Food.APPLE);
        assertEquals( appleApproachTwo.fromValueJava8("APPLE2"),  Food.APPLE);
        assertEquals( appleApproachTwo.fromValueJava8("APPLE3"),  Food.APPLE);
        assertEquals( appleApproachTwo.fromValueJava8("apple3"),  Food.APPLE);
        assertEquals( appleApproachOne.fromValueJava8("apple4"),  Food.NONE);
        assertEquals( appleApproachTwo.fromValueJava8(null),      Food.NONE);
    }
}

As others have suggested, using a Map would be better: 正如其他人所建议的那样,使用Map会更好:

import java.util.EnumSet;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TernaryCondition {

    public enum Food {
        APPLE, APPLE2, APPLE3, BANANA, PINEAPPLE, CUCUMBER;

        private static final EnumSet<Food> APPLES = EnumSet.of(APPLE, APPLE2, APPLE3);

        private static final Map<String, Food> MAP = Stream.of(
            Food.values()).collect(
            Collectors.toMap(
                f -> f.name().toLowerCase(), 
                f -> APPLES.contains(f) ? APPLE : f));

        public static Food fromValue(String value) {
            return MAP.get(value.toLowerCase());
        }
    }

    public static void main(String[] args) {
        Food f = Food.fromValue("apple2");

        System.out.println(f); // APPLE
    }
}

I'd also make fromValue() method static and APPLES an EnumSet . 我还将fromValue()方法fromValue() static并将APPLES fromValue() EnumSet While I realise this answer is very similar to @Holger's, I just wanted to show another approach to build the map. 虽然我意识到这个答案与@ Holger非常相似,但我只是想展示另一种构建地图的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在返回具有多个条件的布尔值的方法上使用流 - How to use stream on method that return boolean value with multiple condition 如何在返回 boolean 值的方法上使用 stream - How to use stream on method that return boolean value with condition 如何解决 Spring Cloud Stream 中的“IllegalArgumentException:无法为返回值的方法设置条件”? - How to solve 'IllegalArgumentException: Cannot set a condition for methods that return a value' in Spring Cloud Stream? 返回值的三元运算符 - Java/Android - Ternary operator to return value- Java/Android Java 8 stream 过滤器返回第一条件满足 - Java 8 stream filter return first condition meet 简化复杂的三元条件 - Simplify complicated ternary condition 我们可以写一个没有返回值的三元运算符 - Can we write an ternary operator without a return value 如何在 JSP 三元运算中使用 scriptlet 值? - How to use a scriptlet value in JSP ternary operation? 如何在数据绑定的同时在android XML中编写三元运算条件 - How to write Ternary operation condition in android XML while data binding 如何在jstl中使用三元运算符编写if else条件? - How to write if else condition using ternary operator in jstl?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM