lambda 表达式 Java vs JS
2011 年 4 月 2 日
函数式编程可以让代码更简洁易懂,更人性化,在主流编程语言中大行其道,像scala, python这些语言都是完全函数式编程语言。而java与javascript这两门前后端分别用得最广泛的语言,也与时俱进各自支持了函数式编程,下面就对它们从各方面进行对比:
1 遍历
2 过滤
3 映射
4 聚合(reduce)
5 分组
6 扁平化
7 结论
1 遍历
- java代码
List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); list.forEach(System.out::print); list.forEach(item->System.out.println(item));
- 运行结果
- javascript代码
let list = [1,2,3,4,5,6,7,8,9]; list.forEach(item=>console.log(item));
- 运行结果
-
小结
在遍历数组/集合的时候,java与javascript语法很类似,不分上下。
2 过滤
- java代码
// 过滤出奇数项 List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); List oddlist = list.stream().filter(item -> item % 2 == 1) .collect(Collectors.toList()); oddlist.forEach(System.out::println);
- 结果
- javascript代码
// 过滤出奇数项 let list = [1,2,3,4,5,6,7,8,9]; let oddList = list.filter(item=>item % 2==1); oddList.forEach(item=>console.log(item));
- 结果
-
小结
在过滤场景中,java需要先把集合转成流(stream),然后再做过滤,而且需要对过滤后的流进行收集(collect),代码显示冗长,多余;相比之下,javascript就非常简洁,代码量少,略胜一筹。
3 映射
映射是把一个对象A通过一定的规则转换成B,经常用在DTO与Enitiy互相转换,或者需要把当前对象构造成接口所需要的格式的场景下。
- java代码
people类
public class People { // id private Long id; // 姓名 private String name; // 性别 private Integer gender; public People(Long id, String name, Integer gender) { this.id = id; this.name = name; this.gender = gender; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } }
dto类
package cn.weiyisoft.platform.wms.service; public class PeopleDto { // id private Long id; // 姓名 private String name; // 性别(0:女,1:男) private Integer gender; // 性别 label private String genderLabel; public PeopleDto() { } public PeopleDto(Long id, String name, Integer gender, String genderLabel) { this.id = id; this.name = name; this.gender = gender; this.genderLabel = genderLabel; } @Override public String toString() { return "PeopleDto{" + "id=" + id + ", name='" + name + '\'' + ", gender=" + gender + ", genderLabel='" + genderLabel + '\'' + '}'; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getGender() { return gender; } public void setGender(Integer gender) { this.gender = gender; } public String getGenderLabel() { return genderLabel; } public void setGenderLabel(String genderLabel) { this.genderLabel = genderLabel; } }
转换代码
// entity 转成 dto List peopleList = Lists.newArrayList(); peopleList.add(new People(10001L, "张三", 0)); peopleList.add(new People(10002L, "李四", 1)); peopleList.add(new People(10003L, "王五", 0)); List peopleDtoList = peopleList.stream().map(item -> { PeopleDto peopleDto = new PeopleDto(); peopleDto.setId(item.getId()); peopleDto.setName(item.getName()); peopleDto.setGender(item.getGender()); peopleDto.setGenderLabel(Objects.equals(item.getGender(), 1) ? "男" : "女"); return peopleDto; }).collect(Collectors.toList()); peopleDtoList.forEach(System.out::println);
- 结果
PeopleDto{id=10001, name='张三', gender=null, genderLabel='女'} PeopleDto{id=10002, name='李四', gender=null, genderLabel='男'} PeopleDto{id=10003, name='王五', gender=null, genderLabel='女'}
- javascript代码
let peopleList = [{id:1001, name:"张三", gender: 0},{id:1002, name:"李四", gender: 1},{id:1003, name:"王五", gender: 0}]; let perpleDtoList = peopleList.map(item=>({...item, genderLabel: item.gender ===1 ? '男':'女'})); perpleDtoList.forEach(item->console.log(item));
- 结果
{id: 1001, name: "张三", gender: 0, genderLabel: "女"} {id: 1002, name: "李四", gender: 1, genderLabel: "男"} {id: 1003, name: "王五", gender: 0, genderLabel: "女"}
-
小结
java所限于刻板的语言结构,需要写太多太多代码了,setter,getter,构造方法这些代码冗余太多,就算用lombok进行简化,也还是需要几十行的代码,反观,javascript利用它ES6中的析构,以及语言天生的动态扩展属性的能力,写出来的代码是这样的简洁明了,完胜java。
4 聚合(reduce)
- java代码
List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); // 选择对每个元素*2,再求和 Integer sum = list.stream().map(item -> item * 2).reduce(0, Integer::sum); System.out.println(sum);
- 结果
- javascript
let list = [1,2,3,4,5,6,7,8,9]; let sum = list.map(item=>item*2).reduce((s, c)=> s+c, 0); console.log(sum);
- 结果
-
结论
java与javascript不相上下。
5 分组
- java代码
List peopleList = Lists.newArrayList(); peopleList.add(new People(10001L, "张三", 0)); peopleList.add(new People(10002L, "李四", 1)); peopleList.add(new People(10003L, "王五", 0)); // 对人员按性别进行分组 Map<Integer, List> genderGroup = peopleList.stream().collect(Collectors.groupingBy(People::getGender)); genderGroup.forEach((k, v)->{ System.out.println("gender:"+ k); System.out.println("value:" + new Gson().toJson(v)); });
- 结果
gender:0 value:[{"id":10001,"name":"张三","gender":0},{"id":10003,"name":"王五","gender":0}] gender:1 value:[{"id":10002,"name":"李四","gender":1}]
- javascript代码
非常遗憾,暂时没找到方法。
6 扁平化
扁平化用于降维非常有用,比如把二维数组降维成一维。
- java代码
// 把二维数组转成一维数组 List<List> list = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), Arrays.asList(7, 8, 9)); List collect = list.stream().flatMap(Collection::stream).collect(Collectors.toList()); collect.forEach(System.out::println);
- 结果
- javascript
// 把二维数组转成一维数组 let list = [[1,2,3],[4,5,6],[7,8,9]]; let flatList = list.flat(); flatList.forEach(item=>console.log(item))
- 结果
-
小结
在扁平化功能上,js也更简洁,而且可以通过 Infinity 作为参数,扁平化无限维度的数组,如下:
let a = [1,[2,3,[4,[5]]]]; a.flat(Infinity); // [1,2,3,4,5] a是4维数组
7 结论
函数式编程作为目前主流的编程方法,确实是非常好用,可以简化代码,避免for, if else这些嵌套,更接近自然语言,也让人更易读懂代码,需要在工作中不断的使用以达到运用自如的目的。
java语言作为一个后端的老牌语言,可以与时俱进,在jdk8中就引入了lambda,已经非常不错,但受限于原有的一些设计,还是需要写太多太多的代码,显示呆板,冗余;相比下,javascript也是前端的老牌语言,在es6规范中引入了函数式编程,让代码更简洁,易懂,是非常好的一门语言。