将Java代码重构为Java8 Stream 风格三则示例
Java8的流风格写法,将for循环体除去,使得语义更加集中于逻辑的处理上,更加便于理解。
这里博主自行写了三个示例,适合对Java8 stream有基本理解的编程者学习,算是抛砖引玉,希望大家能相互交流,如何能更加优雅的写出Stream风格。
示例1
public class findAny {
private static String[] strings = {"a", "b", "c", "c", "d", "e"};
private static List<String> list = Arrays.asList(strings);
private static Stream<String> stream = Stream.of(strings);
private static String listWay(List<String> list) {
String result = null;
for (String s : list) {
System.out.println("list+" + s);
if (s.equals("c")) {
System.out.println("done!");
result = "c";
break;
}
}
return result;
}
private static String streamWay(Stream<String> stream) {
return stream.peek(s1 -> System.out.println("stream+" + s1))
.filter(s -> s.equals("c"))
.peek(s2 -> System.out.println("done!"))
.findFirst().orElse(null);
}
这是最常见的for{...if{...break}}
形式,equals()
判断被等效为filter()
,break
行为被等效为findFirst()
。其实除了findFirst(),还有findAny()方法。二者在串行流下的行为应该是一致的,在并行流下findAny()的返回结果不一定。这里是博主自己的理解,如有错误,欢迎指正!
示例2
public static int listWayCount(List<Ball> balls, String color){
int count=0;
for(Ball ball : balls){
if(ball.getColor().equals(color)){
count++;
}
}
return count;
}
public static int streamWayCount(List<Ball> balls, String color){
return (int) balls.stream().map(Ball::getColor)
.filter(s -> s.equals(color))
.count();
}
这里是一个常见的对包含某种特殊属性的对象的不同来计数的形式。ball.getColor()
等效为了map(Ball::getColor)
,stream中的包含对象由Ball
变成了String
;随后仍然是equals()
等效为filter()
,而count()
方法则完成了for
循环的count++
。
示例3
public static Map<String, Float> legendWay(List<Ball> balls) {
Map<String, Float> result = new HashMap<>();
for(Ball ball : balls){
if(!result.containsKey(ball.getColor())){
result.put(ball.getColor(), 0f);
}
result.put(ball.getColor(),result.get(ball.getColor())+ball.getWeight());
}
return result;
}
public static Map<String, Float> java8Way(List<Ball> balls) {
Map<String, Float> result = new HashMap<>();
for (Ball ball : balls) {
result.putIfAbsent(ball.getColor(), 0f);
result.merge(ball.getColor(), ball.getWeight(), (acc, element) -> acc + element);
}
return result;
}
public static Map<String, Float> streamWay(List<Ball> balls) {
Map<String, Float> result = new HashMap<>();
balls.stream().collect(Collectors.groupingBy(Ball::getColor))
.forEach((k, v) -> result.put(k, v.stream()
.map(Ball::getWeight)
.reduce(0f, ((acc, element) -> acc + element))));
return result;
}
public static void main(String[] args){
List<Ball> balls = Ball.randomBall(100);
System.out.println(legendWay(balls));
System.out.println(java8Way(balls));
System.out.println(streamWay(balls));
}
这个例子的区别是引入了map,但map并不支持stream的方法。这个例子的意思就是统计100个球中各种颜色球的总质量为多少。legendWay是传统写法,也是最糟糕的风格。java8Way是利用Java8中map增加的接口方法的一种写法,相对更加简洁。streamWay是首先利用了Collectors提供的分组方法,在对分组后的各种颜色的球执行map(),reduce(),统计出每种颜色球的总质量。
最后附上Ball的实现
public class Ball {
private static final String[] colors = {"red", "blue", "green", "yellow", "pink", "pepper"};
private static Random r = new Random();
private String color;
private float weight;
private Ball() {
}
private Ball(String color,float weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public float getWeight() {
return weight;
}
public static List<Ball> randomBall(int number) {
List<Ball> balls = new ArrayList<>(number);
for (int i = 0; i < number; i++) {
Ball ball = new Ball(colors[r.nextInt(colors.length)],1f+r.nextFloat()/10f-0.05f);
balls.add(ball);
}
return balls;
}
}