前言:这篇文章涉及的面很浅,只是总结一下jdk8推出的lambda表达式常用的一些功能,至于内部的实现原理,那是不可能的。
这两年,基本所有的公司都由之前的JDK7转战JDK8,还记得上次去饿了么面试给的面试题,第一题就是用lambda实现一个功能,当时对lambda表达式基本是零了解,然后……。现在随着慢慢的使用,也慢慢了解lambda表达式真的是一个好东西,可以大大的简化以前的代码,下面在说常用lambda表达式的时候,会附上对应之前需要的代码量。相信你也会喜欢上它的。
1. 一组对象的分组
场景:Collection下的用户对象集合,根据用户的年龄分组。
代码:
List<User> users = new ArrayList(); //假装数组中有数据
//使用lambda前
Map<Integer, List<User>> userMap = new HashMap<>();
for (User user : users) {
List<User> innerUsers = userMap.get(user.getAge());
if (innerUsers == null) innerUsers = new ArrayList<>();
innerUsers.add(user);
userMap.put(user.getAge(), innerUsers);
}
//使用lambda后
Map<Integer, List<User>> userMap =
users.stream().collect(Collectors.groupingBy(User::getAge));
n行代码直接简化成一行代码,爽歪歪接下来都是一行代码搞定
2. 对象集合抽取字段
场景:标题不想写太长,场景来描述。在实际开发中会经常遇到,两个表有关联,先查询一张表的数据,获取关联另一张表数据的ID集合,然后根据这个ID集合去关联表中查对应的数据。这里就要对ID集合进行抽取。
代码:
List<User> users = new ArrayList<>(); //假装数组中有数据
//使用Lambda前
Set<String> relationIds = new TreeSet<>();
for (User user : users) {
relationIds.add(user.getRelationId());
}
//使用Lambda后
Set<String> relationIds = users.stream()
.map(User::getRelationId).collect(Collectors.toSet());
3. 过滤数据
场景:过滤出所有年龄大于35的程序员。给这些兄弟一人送一张飞机票……
List<User> users = new ArrayList<>();//假装数组中有数据
//使用Lambda前
List<String> userList = new ArrayList<>();
for (User user : users) {
if (Integer.compare(35, u.getAge()) < 0) {
userList.add(user.getRelationId());
}
}
//使用Lambda后
List<User> userList = users.stream()
.filter(u -> Integer.compare(35, u.getAge()) < 0)
.collect(Collectors.toList());
4. 数据排序
场景:根据用户的年龄排序,升序和降序两种。
- 升序:
List<User> users = new ArrayList<>();//假装数组中有数据
//使用Lambda后
List<User> userList = users.stream()
.sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
- 降序
List<User> users = new ArrayList<>();//假装数组中有数据
//使用Lambda后
List<User> userList = users.stream()
.sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList());
这里就不具体单独的写排序逻辑啦,有点麻烦,偷懒一下~
5. 抽取对象唯一标识
这种场景出现的也比较多的,今天在做的功能就用到,刚好做个笔记。
场景:给前端一个列表,前端会对这个列表做增删改查操作。操作完成后传入后端,后端需要查询出之前给前端的列表,然后和现在的列表比对,发生哪些变动,更好的做CRUD操作。这个时候就要把给前端的列表做对象唯一标识抽取。有点抽象,看例子。
List<Article> articles = Lists.newArrayList();//查出来的文章列表
//使用lambda表达式前
Map<Long, Article> articleMap = Maps.newHashMap();
for (Article article : articles) {
articleMap.put(article.getId(), article);
}
//使用lambda表达式后
Map<Long, Article> articleMap =
articles.stream().collect(Collectors.toMap(Article::getId, a -> a));
List<Article> newArticles = Lists.newArrayList();//修改过的文章列表
//使用lambda表达式前
Map<Long, Article> newArticleMap = Maps.newHashMap();
for (Article article : newArticles) {
if (article.getId() != null)
newArticleMap.put(article.getId(), article);
}
//使用lambda表达式后
Map<Long, Article> newArticleMap = newArticles.stream()
.filter(a -> a.getId() != null).collect(Collectors.toMap(Article::getId, a -> a));
这里其实是有一个坑的,Article::getId
要唯一,否则会报Duplicate key
(键重复)异常。上面也提到是唯一标识。
6. 集合求和
给定一个List集合,对List集合内的元素求和
场景:
- List集合内的元素的数值类型的包装类,直接怼元素进行求和
- List集合中是对象,需要对对象内的某个字段进行求和
// 场景1
List<Integer> intList = Lists.newArrayList();
intList.add(10);
intList.add(11);
intList.add(13);
int sum = intList.stream().mapToInt(Integer::intValue).sum();
// 场景2
List<User> userList = Lists.newArrayList();
userList.add(new User(35));
userList.add(new User(26));
userList.add(new User(47));
int sum2 = userList.stream().mapToInt(User::getAge).sum();