我正在尝试自学如何在Java中使用lambda表达式而不是常规的外部迭代类型解决方案。我做了一个简短的程序,我使用整数流并为它们分配等级字母。我没有使用典型的“switch”语句,而是使用了这些lambda表达式。有什么办法可以简化吗?似乎有更好的方法来做到这一点。它有效,但看起来并不整洁。
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
是一个ArrayList。
有什么方法可以将逻辑全部合并到一个流语句中?我试过让他们跟随彼此,但不断得到语法错误。我错过了什么?我试着查看IntStream和Stream的文档,但是找不到我想要的东西。
答案 0 :(得分:5)
只需创建一个单独的函数来映射成绩字母并在单个流中调用它:
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)))
答案 1 :(得分:3)
如果您打开使用第三方库,此解决方案将适用于Java Streams和Eclipse Collections。
List<Integer> grades = List.of(0, 40, 51, 61, 71, 81, 91, 100);
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(new IntCaseFunction<>(x -> x + " -> F")
.addCase(x -> x >= 90, x -> x + " -> A")
.addCase(x -> x >= 80 && x <= 89, x -> x + " -> B")
.addCase(x -> x >= 70 && x <= 79, x -> x + " -> C")
.addCase(x -> x >= 60 && x <= 69, x -> x + " -> D")
.addCase(x -> x >= 50 && x <= 59, x -> x + " -> F"))
.forEach(System.out::println);
这输出以下内容:
0 -> F
40 -> F
51 -> F
61 -> D
71 -> C
81 -> B
91 -> A
100 -> A
我使用了Java 9工厂方法用于List和来自Eclipse Collections的IntCaseFunction。如果没有其他情况匹配,我传递给构造函数的lambda将是默认情况。
数字范围也可以由IntInterval的实例表示,可以使用contains作为方法参考进行测试。以下解决方案将在Java 10中使用局部变量类型推断。
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);
如果我删除所有Predicates
和Functions
并删除IntCaseFunction
并使用三元运算符替换方法引用调用实例方法,则以下操作将起作用。< / p>
@Test
public void grades()
{
var grades = List.of(0, 40, 51, 61, 71, 81, 91, 100);
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(this::gradeToLetter)
.forEach(System.out::println);
}
private IntObjectPair<String> gradeToLetter(int grade)
{
var letterGrade =
grade >= 90 ? "A" :
grade >= 80 ? "B" :
grade >= 70 ? "C" :
grade >= 60 ? "D" : "F";
return PrimitiveTuples.pair(grade, letterGrade);
}
我在这里使用了对的toString()
实现,因此以下将是输出。
0:F
40:F
51:F
61:D
71:C
81:B
91:A
100:A
可以使用对中包含的数字等级和字母等级在forEach中自定义输出。
注意:我是Eclipse Collections的提交者。
答案 2 :(得分:1)
这是一个没有开关/ if的解决方案,否则。
它具有各种条件和动作(打印逻辑)之间的映射
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)));
注意:的
摘要:我更愿意使用switch / if坚持原始代码。
答案 3 :(得分:1)
您可能希望将标记转换为等级(int - &gt; 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);
}
答案 4 :(得分:0)
您可以在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
});
答案 5 :(得分:0)
没有办法去&#34;分叉&#34;流入多个流,如果这是你所追求的。如果您想要在流操作中编写所有逻辑,那么您当前编写它的方式是您可以做的最好的方法。
我认为这里最简单的方法就是编写正常生成字符串的逻辑。如果您想要了解它,可以使用mapToObj
,如下所示:
grades.stream()
.mapToInt(Integer::intValue)
.mapToObj(x -> {
if (x >= 90) {
return "A";
}
//etc
})
.forEach(System.out::println);
答案 6 :(得分:0)
以下代码产生与原始代码完全相同的输出,即以相同的顺序。
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));
});
答案 7 :(得分:-1)
for (int x : grades)
{
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");
else if (x >= 60)
System.out.println(x + " -> D");
else if (x >= 50)
System.out.println(x + " -> F");
}
更容易阅读和运行更快。 PS。那么“E”级呢?