????????Java8中的最大变化就是引入了Lambda表达式,现在都2090年了,还不会用Lambda表达式的同学们可以关注哀家写的文章,让我们一起感受Lambda带来的便利。
? ? ? ? 不是在具体应用场景下写的代码都是耍流氓,所以首先我们建立一个简单的场景。在2090年的我们几乎天天都在刷抖音或拍短视频,抖音中每个账号都是一个用户,我们创建一个User类代表用户,每个用户下可以发布很多短视频作品,我们创建一个Product类代表作品,显而易见,User和Product是一对多的关系,具体代码如下:
/**
* 抖音用户
*/
@Data
@AllArgsConstructor
public class User {
//用户名
private String username;
//作品
private List<Product> 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<User> users = Arrays.asList(zhangtongxue, xiaogui);
? ? ? ? 此时得到的一个用户的集合users,那我们如何筛选出users中的作品时长大于60的作品名称呢?不难想到,用两个for循环就搞定了,如下:
public static Set<String> findProductNames(List<User> users) {
Set<String> 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 Set<String> findProductNames(List<User> users) {
Set<String> 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 Set<String> findProductNames(List<User> users) {
Set<String> 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 Set<String> findProductNames(List<User> users) {
Set<String> 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 Set<String> findProductNames(List<User> users) {
return users.stream()
.flatMap(user -> user.getProducts().stream())
.filter(product -> product.getLength() > 60)
.map(product -> product.getName())
.collect(Collectors.toSet());
}
? ? ? ? 此时我们最终漂亮的代码已经完成,一步一步的完善,慢慢体会Lambda的强大!
|