工作闲下来了,没有活干的时候。我就不知道要做什么了,除了整天在群里聊聊天也没啥意思了。趁着闲杂时间把lambda表达式给学了一下。这里是我整理的一些lambda表达式相关的知识。
基本语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
一句就能写的可以不用带中括号。
使用最频繁的场景是在forEach的时候
下面介绍一下forEach的特殊使用:
//初始化一个1-num的list列表函数
Function<Integer,List<Integer>> intListInit = (Integer nums)->{
List<Integer> ints = new ArrayList<Integer>();
while(ints.size()<nums){
ints.add(ints.size()+1);
}
return ints;
};
//初始化1-100正序的数组
List<Integer> intList = intListInit(100);
//foreach的第一个,使用双冒号操作符
intList.forEach(System.out::println);
//上面那种方式等于下面这种方式:
intList.forEach(num->System.out.println(num));
//将会默认将参数传入到双冒号表达式里面的方法里面
合理使用forEach将会节约很多的代码量,而且可读性也能让你的同事目瞪口呆,这样你的位置也稳了~
到这儿就没了吗?不,接下来我们说一下几种典型的使用的方法,比如上面的Function
Predicate接口
描述:输入一个参数,返回一个布尔类型,一般用于逻辑判断。在这儿我建议这个方法用于列表的filter,直接来看示例吧:
//仍然使用上面那个list
Integer loveNum = 3;//可以提前设置幸运数字
//输入一个字符串,如果能被幸运数字选中,那么返回true
Predicate<Integer> pct = (s) -> (s%loveNum==0);
//使用时调用test方法返回布尔类型
intList.forEach(num->System.out.println(num+"是不是我的幸运数字呢:"+pct.test(num)));
pct.test(3);//也可以直接调用来判断
//注意:这些方法都是interface,即也可以自己封装一些方法
Predicate<Object> pre = Objects::nonNull;
//效果等同于 Predicate<Object> pre = (obj)->Objects.nonNull(obj);
Function接口
描述:接收一个参数,返回一个结果,可以将多个函数串在一起,然后变成复合Funtion(有输入也有输出) 结果,直接来看示例吧:
Function<Integer,String> printValue = e->"没想到最后的结果是:"+e;
Function<Integer,Integer> product = e->e*e;
intlist.forEach(str->System.out.println(product.andThen(printValue).apply(str)));
这里看到我们的运行结果是:
没想到最后的结果是:1
没想到最后的结果是:4
没想到最后的结果是:9
没想到最后的结果是:16
没想到最后的结果是:25
没想到最后的结果是:36
......
Function在使用andThen时优先执行product然后执行printValue,所以这个方法是先执行调用者然后最后执行参数
Consumer接口
和Function不同的是,Consumer没有返回值,该接口有一个输入,但没有输出(就是没有返回值),这个接口一般也可以称为消费者,直接上代码:
List<User> userList = new ArrayList<>();
Consumer<String> addUserList = (p)->{
User user = new User();
user.setId(UUIDUtils.generateUuid());
user.setMobile("17"+Math.random());
user.setPassword(p);
userList.add(user);
};
list.forEach(addUserList::accept);
userList.forEach(user->System.out.println(JSON.toJSONString(user)));
accept方法就能调用这个的接口,同时该接口也支持andThen方法
一些常用的方法讲完了,我们也可以实现自己封装一些接口来实现。现在我们知道了表达式基本可以为下面这些:
()->3; // 无参数返回一个值
(s)->s.trim() //返回一个修改后的字段串
(p1, p2) -> p1 – p2 //接受2个数字(参数),并返回他们的差值
(int p1, int p2) -> p1 – p2 //接受2个数字参数,并返回他们的差值
(Map map)->map.put("db","192.168.0.66");//可能无返回值,做一个有参数但无返回值的消费者
使用Lambdas加stream
Stream对集合进行了包装,同时也和lambda一起使用.Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。原文
intList.stream();//之前的那个列表,使用steam
//steam接口中提供了很多的接口,包括filter,sorted,limit,mapToLong,mapToInt....等方法
//sorted排序
intlist.stream().sorted((x,y)->(y-x)).forEach(System.out::println);//之前是1-100的数,现在变成了100-1的输出
intlist.stream().limit(5);//只取5条
Consumer<User> addUserSalf = obj->{
obj.setSalf(UUIDUtils.generateUuid());
//系统封装的加盐方式,将盐和密码当参数传入,将盐和密码还有安全码加入并MD5,返回MD5的字符串,用于密码安全
obj.setPassword(PasswordHelper.encryptPassword(obj.getSalf(),obj.getPassword()));
};//定义一个快速给用户对象加盐的消费者
userList.stream().filter(obj->StringUtil.isBlank(obj.getSalf()))//过滤密码加过盐的用户信息
.filter(obj->obj.getPassword().indexOf("6")>0)//只显示密码只含有6的数据
.forEach(addUserSalf::accept);//用户列表已经成功将过滤过后的数据加盐
IntSummaryStatistics statistics = intlist.stream().sorted((x,y)->(y-x)).mapToInt(x->x).summaryStatistics();
System.out.println(" 最大值:"+statistics.getMax());
System.out.println(" 平均值:"+statistics.getAverage());
System.out.println(" 最小值:"+statistics.getMin());