将现有条件转换为Java8流
如何将以下条件转换为Java8流将现有条件转换为Java8流,java,java-8,java-stream,Java,Java 8,Java Stream,如何将以下条件转换为Java8流 List<String> name = Arrays.asList("A", "B", "C"); String id; if(name.contains("A")){ id = "123"; }else if(name.contains("B")){ id = "234"; }else if(name.contains("C")){ id = "345";
List<String> name = Arrays.asList("A", "B", "C");
String id;
if(name.contains("A")){
id = "123";
}else if(name.contains("B")){
id = "234";
}else if(name.contains("C")){
id = "345";
}
List name=Arrays.asList(“A”、“B”、“C”);
字符串id;
如果(名称包含(“A”)){
id=“123”;
}如果(名称包含(“B”)){
id=“234”;
}如果(名称包含(“C”)){
id=“345”;
}
我正在学习流,想知道如何转换这个流。我试过使用foreach、map、filter,但它没有达到目的我不明白为什么必须将其转换为流。对我来说,这似乎不是流API的情况。 但如果您想轻松地添加新项并使代码更具可读性,我建议您使用map
private static final ImmutableMap<String, String> nameToId = new ImmutableMap.Builder<String, String>()
.put("A", "123")
.put("B", "234")
.put("C", "345")
.build();
您所描述的问题是如何从一个函数应用到两个输入集(输入值和映射)中获得一个值(id)
id = f(list,mappings)
所以基本上你的问题是,找到一个基于流的f(换句话说,返回列表的解决方案不能解决你的问题)
首先,最初的if-else-if-else构造混合了三个关注点:
- 输入验证(仅考虑值集“A”、“B”、“C”)
- 将输入值映射到输出值(“A”->“123”、“B”->“234”、“C”->“345”)
- 根据输入值的自然顺序定义输入值的隐含优先级(不确定这是有意的还是无意的),“A”在“B”之前,在“C”之前
- 一个过滤函数,它忽略所有没有映射的输入值
- 映射器函数,将输入映射到id
- Reduce函数(二进制运算符)执行if-else-if-else构造隐含的优先级逻辑
Function<String,Optional<String>> idMapper = s -> {
if("A".equals(s)){
return Optional.of("123");
} else if("B".equals(s)){
return Optional.of("234");
} else if("C".equals(s)){
return Optional.of("345");
}
return Optional.empty();
} ;
最终结果
总而言之,对于您的特定问题,使用流和输入验证的最简洁版本(不首先定义函数)是:
//define the mapping in an immutable map (that's just one way to do it)
final Map<String,String> mapping = Collections.unmodifiableMap(
new HashMap<String,String>(){{
put("A", "123");
put("B", "234");
put("C", "345");
}});
Optional<String> result = Arrays.asList("C", "D", "A", "B")
.stream()
.filter(mapping::containsKey)
.min(Comparator.naturalOrder())
.flatMap(s -> Optional.ofNullable(mapping.get(s)));
//在不可变映射中定义映射(这只是一种方法)
最终映射=集合。不可修改映射(
新HashMap(){{
将(“A”、“123”);
付诸表决(“B”、“234”);
付诸表决(“C”、“345”);
}});
可选结果=Arrays.asList(“C”、“D”、“A”、“B”)
.stream()
.filter(映射::containsKey)
.min(比较器.naturalOrder())
.flatMap(s->Optional.ofNullable(mapping.get(s));
以下哪一项是f:
双功能f=
(list,map)->list.stream()
.filter(映射::containsKey)
.min(比较器.naturalOrder())
.flatMap(s->Optional.ofNullable(mapping.get(s));
这种方法当然有一定的吸引力,但if-else方法的简洁性带来的优雅也不容否认;)
但为了完整性,让我们看看复杂性。假设映射的数量和输入值的数量相当大(否则就无关紧要了)
基于在地图上迭代并使用contains搜索的解决方案(如在if-else构造中):
- 最佳情况:o(1)(if-else构造中的第一个分支,列表中的第一项)
- 最坏情况:O(n^2)(if-else构造中的最后一个分支,列表中的最后一项)
- 最佳案例:o(n)
- 最坏情况:O(n)
Thx对Hamlezz提出了reduce思想,Holger指出将mapper函数直接应用于流不会产生相同的结果(因为第一场比赛获胜,而不是if else构造中的第一个条目)和min(Comparator.naturalOrder())选项。受Serghey Bishyr使用地图的答案的启发,我也使用了地图(但有序)我宁愿通过地图的键而不是列表来找到合适的id。这当然可能不是最好的解决方案,但您可以这样玩
Stream
s;-)
Map nameToId=newlinkedhashmap();
//以下顺序反映了您的条件顺序!(如果您的第一个条件包含“B”,您将在第一个位置移动“B”)
nameToId.put(“A”、“123”);
nameToId.put(“B”,“234”);
nameToId.put(“C”、“345”);
列表名称=数组.asList(“A”、“B”、“C”);
String id=nameToId.keySet()
.stream()
.filter(名称::包含)
.findFirst()
.map(nameToId::get)
.orElse(空)
你真的一无所获。。。不要试图在过滤谓词或映射函数中添加太多内容,因为这样您的流解决方案可能不再那么可读。另一个(但紧凑的)解决方案:
Arrays.asList("B", "C", "A", "D").stream()
.map(s -> s.equals("A") ? new SimpleEntry<>(1, "123")
: s.equals("B") ? new SimpleEntry<>(2, "234")
: s.equals("C") ? new SimpleEntry<>(3, "345")
: null)
.filter(x -> x != null)
.reduce((a, b) -> a.getKey() < b.getKey() ? a : b)
.map(Entry::getValue)
.ifPresent(System.out::println);
Arrays.asList(“B”、“C”、“A”、“D”).stream()
.map(s->s.equals(“A”)?新的SimpleEntry(1,“123”)
:s.equals(“B”)?新单纯形(2,“234”)
:s.equals(“C”)?新单纯形(3,“345”)
:null)
.filter(x->x!=null)
.reduce((a,b)->a.getKey()
我正在学习流,想知道如何转换这个流。我试过使用foreach、map、filter,但没有达到目的。您的实际代码并不清楚所需的行为是什么,因为它并不是简单地将一个值映射到另一个值,而是根据检查顺序以优先级检查列表中的元素。在我看来,这是一个糟糕的代码,它应该作为一个包含多个返回语句的方法来实现,而不是“else-if”链接。这里的整个上下文都在将代码转换为流。N
Predicate<String> filter = s -> mapping.containsKey(s);
BinaryOperator<String> prioritizer = (a, b) -> a.compareTo(b) < 0 ? a : b;
Optional<String> id = Arrays.asList("C", "B", "A")
.stream()
.filter(filter) //concern: input validation
.reduce(prioritizer) //concern: prioritization
.flatMap(idMapper); //concern: id-mapping
//define the mapping in an immutable map (that's just one way to do it)
final Map<String,String> mapping = Collections.unmodifiableMap(
new HashMap<String,String>(){{
put("A", "123");
put("B", "234");
put("C", "345");
}});
Optional<String> result = Arrays.asList("C", "D", "A", "B")
.stream()
.filter(mapping::containsKey)
.min(Comparator.naturalOrder())
.flatMap(s -> Optional.ofNullable(mapping.get(s)));
BiFunction<List<String>,Map<String,String>,Optional<String>> f =
(list,map) -> list.stream()
.filter(map::containsKey)
.min(Comparator.naturalOrder())
.flatMap(s -> Optional.ofNullable(mapping.get(s)));
Map<String, String> nameToId = new LinkedHashMap<>();
// the following order reflects the order of your conditions! (if your first condition would contain "B", you would move "B" at the first position)
nameToId.put("A", "123");
nameToId.put("B", "234");
nameToId.put("C", "345");
List<String> name = Arrays.asList("A", "B", "C");
String id = nameToId.keySet()
.stream()
.filter(name::contains)
.findFirst()
.map(nameToId::get)
.orElse(null)
Arrays.asList("B", "C", "A", "D").stream()
.map(s -> s.equals("A") ? new SimpleEntry<>(1, "123")
: s.equals("B") ? new SimpleEntry<>(2, "234")
: s.equals("C") ? new SimpleEntry<>(3, "345")
: null)
.filter(x -> x != null)
.reduce((a, b) -> a.getKey() < b.getKey() ? a : b)
.map(Entry::getValue)
.ifPresent(System.out::println);