Java8中lambda表达式的应用及一些泛型相关知识
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利
顺带用到一些泛型编程,一切都是为了简化代码
场景:
一个数据类,用于记录职工信息
publicclassEmployee{ publicStringname; publicintage; publiccharsex; publicStringtime; publicintsalary; }
我们有一列此类数据
List<Employee>data=Arrays.asList(e1,e2,e3......)
现在有需求:将员工Employee按照姓名的首字母(假设均为英文名)进行分组:
那么我们要得到的结果应该是一个Map:char->List<Employee>这样的映射关系
publicstaticMap<Character,List<Employee>>groupByFirstChar( List<Employee>data){ Map<Character,List<Employee>>result=newHashMap<>(); for(Employeee:data){ Characterc=e.name.charAt(0); List<Employee>l=result.get(c); if(l==null){ l=newArrayList<>(); result.put(c,l); } l.add(e); } returnresult; }
代码并不复杂,很快就可以完成,老板看你效率这么高,于是说,再按照工资分个组吧,5000以下的,5000~10000的...等
也不会太难,将key换一下,稍作逻辑处理即可
publicstaticMap<String,List<Employee>>groupBySalary(List<Employee>data){ Map<String,List<Employee>>result=newHashMap<>(); for(Employeee:data){ Stringkey=separate(e.salary); List<Employee>l=result.get(key); if(l==null){ l=newArrayList<>(); result.put(key,l); } l.add(e); } returnresult;<br>} privatestaticStringseparate(intsalary){ if(salary<=5000){ return"5000以下"; } if(salary<=10000){ return"5000~10000"; } if(salary<=20000){ return"10000~20000"; } return"20000以上" }
然后老板又说了,按照员工的入职年份分下组吧。。。
这里就代码就不写了,稍作比较可以发现,无论怎么分组,唯一的变化是key值的选取方式,
第一次将Employee的name的第一字母作为key:
Employeee->e.name.charAt(0)
第二次将Employee的salary按照方法separat转换为String作为key:
Employeee->separate(e.salary):String
以此类推
Employeee->getYear(e.time):String
事实上第一次也可以将获取首字母单独写成一个方法
Employeee->getFirstChar(e.name):Character
为了看起来更美观,可以讲三个方法的参数都设置成Employee方法体就不写了这里只列出参数和返回值
Employeee->getFirstChar(e):Character Employeee->separate(e):String Employeee->getYear(e):String
->的左边为参数,:的右边为返回值,->的右边是方法的签名
那么我们自然会想到将变化的部分抽取为参数,其他不变的部分抽取为方法体,那么就可以省去那些重复的代码,显然变化的部分就是上面列出的,将Employeee转化成key的方法,但是我们知道java是不能把方法作为参数进行传递的。不过对于稍有经验的程序猿来说这并不是问题,我们可以使用接口来实现我们的目的,同时又会遇到另一个问题,以上三个方法的返回值是不同的,因此我们要用到泛型:
publicstatic<K>Map<K,List<Employee>>groupByKey(List<Employee>data,GetKey<K>getKey){ Map<K,List<Employee>>result=newHashMap<>(); for(Employeee:data){ Kkey=getKey.getKey(e); List<Employee>l=result.get(key); if(l==null){ l=newArrayList<>(); result.put(key,l); } l.add(e); } returnresult; } interfaceGetKey<K>{ KgetKey(Employeee); }
那么上面的第一个需求就可以这样实现
Map<Character,List<Employee>>result=groupByKey(data,newGetKey<Character>(){ @Override publicCharactergetKey(Employeee){ e.name.charAt(0); } });
第二个需求
Map<String,List<Employee>>result=groupByKey(list,newGetKey<String>(){ @Override publicStringgetKey(Employeee){ separate(e.salary); } });
可以发现,我们只需要更改泛型参数和匿名内部类的实现即可,唯一的问题恐怕是这么写实在不太好看,而且很多例行公事的代码,尤其体现在匿名内部类上。
事实上我们只关心这个匿名内部类的参数和返回值,其他部分仅仅是语法要求。
java8恰好为我们提供了很好的方式来避免复杂的例行公事的方式:lambda表达式,以上实现就可以写成
Map<Character,List<Employee>>resultByFirstChar=groupByKey(list,e->e.name.charAt(0)); Map<String,List<Employee>>resultBySalary=groupByKey(list,e->separate(e.salary));
lambda表达式恰恰只表现出我们所关心的,参数和返回值,同时由于类型推断,可以省去参数类型,具体语法这里就不介绍了,网上可以查到很多资料
extra:
如果你对泛型有不错的了解的话,方法groupByKey还可以进一步抽象:
publicstatic<K,E>Map<K,List<E>>groupBy(List<?extendsE>data,Function<?superE,?extendsK>fun){ Map<K,List<E>>result=newHashMap<>(); for(Ee:data){ Kk=fun.apply(e);<br>List<E>l=result.get(k); if(l==null){ l=newArrayList<>(); result.put(k,l); } l.add(e); } returnresult;<br> }
我们将Employee这个类也抽取了,好处显而易见
Function接口是java8新加入的接口:
@FunctionalInterface publicinterfaceFunction<T,R>{ Rapply(Tt); }
输入一个T类型返回R类型。泛型和函数式编程结合的很不错,虽然java8的新特性被各种吐槽,但是能带来好处总是好的,这给了我们更多的选择。
有时间的话会介绍stream,java8的另一大利器
以上所述是小编给大家介绍的Java8中lambda表达式的应用及一些泛型相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!