我想根据条件返回流的值。以下面的示例为例,我想将任何苹果映射到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);
}
}
如何在流中包含三元条件?
答案 0 :(得分:3)
你可以这样做:
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());
}
}
地图中的查询将为O(1)
。
答案 1 :(得分:2)
正如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);
}
答案 2 :(得分:2)
三元运营商没有什么特别之处。因此,您只需将此映射操作添加到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);
}
但是,这些线性搜索都不是必需的。使用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);
}
}
它将根据需要执行不区分大小写的查找,并初始化为首先返回APPLE
替换,因此不需要进行额外的比较。
答案 3 :(得分:2)
根据之前的答案,特别是@Alexis,我写了一些代码来检查booth方法(来自Java 7和Java 8)。也许这对Java 8上的新用户有用。
所以,我在原始答案中做了一些改动。首先,我进行了一些单元测试,并添加了两个包装方法 verifyNames()和包含()。其次,我们可以在发生意外操作时使用默认行为,在这种情况下,当使用 null 调用 appleApproachTwo.fromValueJava8()时不存在枚举值。
最后,最后一次更改使用 java.util.Optional 对象的潜在用途。在这种情况下,我们可以保护环境因为与null对象不一致而崩溃。有关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);
}
}
答案 4 :(得分:0)
正如其他人所建议的那样,使用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
}
}
我还将fromValue()
方法static
和APPLES
设为EnumSet
。虽然我意识到这个答案与@ Holger非常相似,但我只是想展示另一种构建地图的方法。