在Java中简化流上的Lambda表达式
我试图教自己如何在Java中使用lambda表达式,而不是常规的外部迭代类型解决方案。我做了一个简短的程序,我用一个整数流给它们赋值。我没有使用典型的“switch”语句,而是使用了这些lambda表达式。有什么方法可以简化它吗?看来有更好的办法。它能工作,但看起来不那么整洁在Java中简化流上的Lambda表达式,java,lambda,java-stream,Java,Lambda,Java Stream,我试图教自己如何在Java中使用lambda表达式,而不是常规的外部迭代类型解决方案。我做了一个简短的程序,我用一个整数流给它们赋值。我没有使用典型的“switch”语句,而是使用了这些lambda表达式。有什么方法可以简化它吗?看来有更好的办法。它能工作,但看起来不那么整洁 grades.stream() .mapToInt(Integer::intValue) .filter(x -> x >= 90) .for
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 90)
.forEach(x -> System.out.println(x + " -> A"));
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 80 && x <= 89)
.forEach(x -> System.out.println(x + " -> B"));
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 70 && x <= 79)
.forEach(x -> System.out.println(x + " -> C"));
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 60 && x <= 69)
.forEach(x -> System.out.println(x + " -> D"));
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 50 && x <= 59)
.forEach(x -> System.out.println(x + " -> F"));
grades.stream()
.mapToInt(整数::intValue)
.过滤器(x->x>=90)
.forEach(x->System.out.println(x+“->A”);
等级.溪流()
.mapToInt(整数::intValue)
.filter(x->x>=80&&x System.out.println(x+“->B”);
等级.溪流()
.mapToInt(整数::intValue)
.filter(x->x>=70&&x System.out.println(x+“->C”);
等级.溪流()
.mapToInt(整数::intValue)
.filter(x->x>=60&&x System.out.println(x+“->D”);
等级.溪流()
.mapToInt(整数::intValue)
.filter(x->x>=50&&x System.out.println(x+“->F”);
grades
是一个数组列表
有什么方法可以将逻辑全部合并到一个流语句中吗?我试着让他们互相跟踪,但总是出现语法错误。我错过了什么?我试图查看IntStream和Stream的文档,但实际上找不到我要查找的内容。您可以在
forEach
语句中添加这些条件,如
grades.stream()
.mapToInt(Integer::intValue)
.forEach(x -> {
if (x >= 90)
System.out.println(x + " -> A");
else if (x >= 80)
System.out.println(x + " -> B");
else if (x >= 70)
System.out.println(x + " -> C");
......
// other conditions
});
更容易阅读,运行速度更快。
ps.“E”等级如何?只需创建一个单独的函数来映射等级字母,并在单个流中调用:
static char gradeLetter(int grade) {
if (grade >= 90) return 'A';
else if (grade >= 80) return 'B';
else if (grade >= 70) return 'C';
else if (grade >= 60) return 'D';
else return 'F';
}
grades.stream()
.mapToInt(Integer::intValue)
.filter(x -> x >= 50)
.forEach(x -> System.out.println(x + " -> " + gradeLetter(x)));
如果您特别注重按等级对结果进行排序,可以在流的开头添加排序:
.sorted(Comparator.comparing(x -> gradeLetter(x)))
如果您愿意使用第三方库,此解决方案将与Java流和 我对列表和Eclipse集合使用了Java9工厂方法。如果其他情况都不匹配,则传递给构造函数的lambda将是默认情况 数字范围还可以由的实例表示,可以使用contains作为方法引用对其进行测试。以下解决方案将在Java10中使用局部变量类型推断
var mapGradeToLetter = new IntCaseFunction<>(x -> x + " -> F")
.addCase(x -> x >= 90, x -> x + " -> A")
.addCase(IntInterval.fromTo(80, 89)::contains, x -> x + " -> B")
.addCase(IntInterval.fromTo(70, 79)::contains, x -> x + " -> C")
.addCase(IntInterval.fromTo(60, 69)::contains, x -> x + " -> D")
.addCase(IntInterval.fromTo(50, 59)::contains, x -> x + " -> F");
var grades = List.of(0, 40, 51, 61, 71, 81, 91, 100);
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(mapGradeToLetter)
.forEach(System.out::println);
我在这里使用的是该对的toString()
实现,因此以下是输出
0:F
40:F
51:F
61:D
71:C
81:B
91:A
100:A
可以在forEach中使用该对中包含的数字等级和字母等级定制输出
注意:我是Eclipse集合的提交者 这里有一个没有开关/if,else的解决方案 它在各种条件和动作之间有映射(打印逻辑)
Map actions=newlinkedhashmap();
//当心列表中的空值-取消装箱时可能会导致NullPointerException
actions.put(x->x>=90,x->System.out.println(x+“->A”);
actions.put(x->x>=80&&x System.out.println(x+“->B”);
actions.put(x->x>=70&&x System.out.println(x+“->C”);
actions.put(x->x>=60&&x System.out.println(x+“->D”);
actions.put(x->x>=50&&x System.out.println(x+“->F”);
grades.forEach(x->actions.entrySet().stream())
.filter(entry->entry.getKey().apply(x))
.findFirst()
.ifPresent(entry->entry.getValue().accept(x));
注:
mapToObj
,如下所示:
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(x -> {
if (x >= 90) {
return "A";
}
//etc
})
.forEach(System.out::println);
您需要分离将标记转换为等级(int->String)和循环遍历arraylist的逻辑 使用流作为循环数据的机制和转换逻辑的方法 下面是一个简单的例子
private static void getGradeByMarks(Integer marks) {
if(marks > 100 || marks < 0) {
System.err.println("Invalid value " + marks);
return;
}
// whatever the logic for your mapping is
switch(marks/10) {
case 9:
System.out.println(marks + " --> " + "A");
break;
case 8:
System.out.println(marks + " --> " + "B");
break;
case 7:
System.out.println(marks + " --> " + "C");
break;
case 6:
System.out.println(marks + " --> " + "D");
break;
default:
System.out.println(marks + " --> " + "F");
break;
}
}
public static void main(String[] args) {
List<Integer> grades = Arrays.asList(90,45,56,12,54,88,-6);
grades.forEach(GradesStream::getGradeByMarks);
}
private static void getGradeByMarks(整数标记){
如果(标记>100 | |标记<0){
System.err.println(“无效值”+标记);
返回;
}
//不管映射的逻辑是什么
开关(标记/10){
案例9:
System.out.println(标记+“-->”+“A”);
打破
案例8:
System.out.println(标记+“-->”+“B”);
打破
案例7:
System.out.println(标记+“-->”+“C”);
打破
案例6:
System.out.println(标记+“-->”+“D”);
打破
违约:
System.out.println(标记+“-->”+“F”);
打破
}
}
公共静态void main(字符串[]args){
列表等级=数组。asList(90,45,56,12,54,88,-6);
grades.forEach(GradesStream::getGradeByMarks);
}
以下代码生成的输出与原始代码完全相同,即顺序相同
grades.stream()
.filter(x -> x >= 50)
.collect(Collectors.groupingBy(x -> x<60? 'F': 'E'+5-Math.min(9, x/10)))
.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.flatMap(e -> e.getValue().stream().map(i -> String.format("%d -> %c", i, e.getKey())))
.forEach(System.out::println);
grades.stream()
.过滤器(x->x>=50)
.collect(收集器.groupingBy(x->x e.getValue().stream().map(i->String.format(“%d->%c”,即getKey()))
.forEach(System.out::println);
如果不需要该顺序,可以省略分组和排序步骤:
grades.stream()
.filter(x -> x >= 50)
.map(x -> String.format("%d -> %c", x, x<60? 'F': 'E'+5-Math.min(9, x/10)))
.forEach(System.out::println);
grades.stream()
.过滤器(x->x>=50)
.map(x->String.format(“%d->%c”,x,x>=50)
.forEach(x->System.out.printf(“%d->%c%n”,x,x{
如果(x>=50)System.out.printf(“%d->%c%n”,x,xLambda)与否,无论在可读性和可用性方面,好的旧开关肯定是更好的方法
Map<Predicate<Integer>, Consumer<Integer>> actions = new LinkedHashMap<>();
//Beware of nulls in your list - It can result in a NullPointerException when unboxing
actions.put(x -> x >= 90, x -> System.out.println(x + " -> A"));
actions.put(x -> x >= 80 && x <= 89, x -> System.out.println(x + " -> B"));
actions.put(x -> x >= 70 && x <= 79, x -> System.out.println(x + " -> C"));
actions.put(x -> x >= 60 && x <= 69, x -> System.out.println(x + " -> D"));
actions.put(x -> x >= 50 && x <= 59, x -> System.out.println(x + " -> F"));
grades.forEach(x -> actions.entrySet().stream()
.filter(entry -> entry.getKey().apply(x))
.findFirst()
.ifPresent(entry -> entry.getValue().accept(x)));
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(x -> {
if (x >= 90) {
return "A";
}
//etc
})
.forEach(System.out::println);
private static void getGradeByMarks(Integer marks) {
if(marks > 100 || marks < 0) {
System.err.println("Invalid value " + marks);
return;
}
// whatever the logic for your mapping is
switch(marks/10) {
case 9:
System.out.println(marks + " --> " + "A");
break;
case 8:
System.out.println(marks + " --> " + "B");
break;
case 7:
System.out.println(marks + " --> " + "C");
break;
case 6:
System.out.println(marks + " --> " + "D");
break;
default:
System.out.println(marks + " --> " + "F");
break;
}
}
public static void main(String[] args) {
List<Integer> grades = Arrays.asList(90,45,56,12,54,88,-6);
grades.forEach(GradesStream::getGradeByMarks);
}
grades.stream()
.filter(x -> x >= 50)
.collect(Collectors.groupingBy(x -> x<60? 'F': 'E'+5-Math.min(9, x/10)))
.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.flatMap(e -> e.getValue().stream().map(i -> String.format("%d -> %c", i, e.getKey())))
.forEach(System.out::println);
grades.stream()
.filter(x -> x >= 50)
.map(x -> String.format("%d -> %c", x, x<60? 'F': 'E'+5-Math.min(9, x/10)))
.forEach(System.out::println);
grades.stream()
.filter(x -> x >= 50)
.forEach(x -> System.out.printf("%d -> %c%n", x, x<60? 'F': 'E'+5-Math.min(9, x/10)));
grades.forEach(x -> {
if(x >= 50) System.out.printf("%d -> %c%n", x, x<60? 'F': 'E'+5-Math.min(9, x/10));
});