Java8中的最大变化就是引入了Lambda表达式,现在都2090年了,还不会用Lambda表达式的同学们可以关注哀家写的文章,让我们一起感受Lambda带来的便利。
不是在具体应用场景下写的代码都是耍流氓,所以首先我们建立一个简单的场景。在2090年的我们几乎天天都在刷抖音或拍短视频,抖音中每个账号都是一个用户,我们创建一个User类代表用户,每个用户下可以发布很多短视频作品,我们创建一个Product类代表作品,显而易见,User和Product是一对多的关系,具体代码如下:
@Data
@AllArgsConstructor
public class User {
//用户名
private String username;
//作品
private List products;
}
@Data
@AllArgsConstructor
public class Product {
//作品名称
private String name;
//作品时长
private Integer length;
}
例如现在有两个抖音用户,分别为张同学和小鬼,他们都有自己的作品,现在我们用分别初始化一下User和Product,造一些数据,代码如下:
User zhangtongxue = new User("张同学", Arrays.asList(
new Product("农村生活1", 60),
new Product("农村生活2",30),
new Product("农村生活3",20),
new Product("农村生活4",63),
new Product("农村生活5",80)
));
User xiaogui = new User("小鬼", Arrays.asList(
new Product("撩妹1", 70),
new Product("撩妹2",35),
new Product("撩妹3",23)
));
List users = Arrays.asList(zhangtongxue, xiaogui);
此时得到的一个用户的集合users,那我们如何筛选出users中的作品时长大于60的作品名称呢?不难想到,用两个for循环就搞定了,如下:
public static SetfindProductNames(List users) { Set productNames = new HashSet<>(); for (User user : users) { for (Product product : user.getProducts()) { if (product.getLength() > 60) { String name = product.getName(); productNames.add(name); } } } return productNames; }
上面的代码很传统,索然无味,如果使用lambda是不是很酸呢,下面我们使用Stream的方式对上面的代码进行重构,首先使用forEach替换掉for循环。
public static SetfindProductNames(List users) { Set productNames = new HashSet<>(); users.stream() .forEach(user -> { user.getProducts().stream() .forEach(product -> { if (product.getLength() > 60) { String name = product.getName(); productNames.add(name); } }); }); return productNames; }
上面代码中虽然使用了流,但是并没有发挥它的作用,事实上还不如两个for循环的代码好呢!因此,是时候引入更符合流风格的代码了,如下:
public static SetfindProductNames(List users) { Set productNames = new HashSet<>(); users.stream() .forEach(user -> { user.getProducts().stream() .filter(product -> product.getLength() > 60) .map(product -> product.getName()) .forEach(name -> productNames.add(name)); }); return productNames; }
现在使用了更符合流风格的代码替换了内层forEach循环,但代码看起来还是非常的繁琐,各种流嵌套起来非常的糟糕。理想的操作莫过于找到一种方法,将用户转化成一个作品的Stream,因为用户是多个,采用flatMap操作,可以把多个Stream合并成一个Stream,代码如下:
public static SetfindProductNames(List users) { Set productNames = new HashSet<>(); users.stream() .flatMap(user -> user.getProducts().stream()) .filter(product -> product.getLength() > 60) .map(product -> product.getName()) .forEach(productName -> productNames.add(productName)); return productNames; }
这时候代码就比较干净了,也符合了lambda流式操作风格,但是还存在一点问题,就是上述代码仍需手动创建一个Set集合,然后把结果add到集合中。我们希望看到的是整个计算任务是由一连串的Stream操作完成,也就是链式风格的代码要统一,因此我们想到了收集器,即Collectors,下面我们再次修改代码如下:
public static SetfindProductNames(List users) { return users.stream() .flatMap(user -> user.getProducts().stream()) .filter(product -> product.getLength() > 60) .map(product -> product.getName()) .collect(Collectors.toSet()); }
此时我们最终漂亮的代码已经完成,一步一步的完善,慢慢体会Lambda的强大!



