读了《java 8函数式编程》,总结一下其中的常用方法,方便平常使用;
目录
函数式编程
-
其核心是:在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值;
-
面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象;
Lambda表达式
-
是一个匿名方法,将行为像数据一样进行传递;
-
其类型依赖于上下文环境,是由编译器推断出来的;
-
常见结构:BinaryOperator<Integer> add = (x, y) -> x + y;
Stream-流
-
Stream是用函数式编程方式在集合类上进行复杂操作的工具,是一种内部迭代方式;
-
通过Stream暴露集合的最大优点在于,它很好的封装了内部实现的数据结构。仅暴露了一个Stream接口,用户在实际操作中无论如何使用,都不会影响内部的List或Set;
1、惰性求值 VS. 及早求值
惰性求值方法:返回值是Stream,没有产生新的集合;
及早求值方法:最终会从Stream产生值,返回的是另一个值或为空;
2、常用的流操作
//of:使用一组初始值生成新的Stream;
//collect(Collectors.toList()):由Stream里的值生成一个列表,是一个及早求值操作;
List<String> list1 = Stream.of("a", "b", "hello")
.collect(Collectors.toList());
assert list1.equals(Arrays.asList("a", "b", "hello"));
//collect(Collectors.toSet()):由Stream里的值生成一个set
Set<String> set1 = Stream.of("a", "hello", "a")
.collect(Collectors.toSet());
//返回值:[a, hello]
//map:将一种类型的值转化成另外一种类型,从而实现将一个流中的值转化成一个新的流;
List<String> list2 = Stream.of("a", "b", "hello")
.map(e -> e.toUpperCase())
.collect(Collectors.toList());
assert list2.equals(Arrays.asList("A", "B", "HELLO"));
//filter:和if条件语句的功能相同,过滤掉不符合条件的,保留符合条件的;
List<String> list3 = Stream.of("c", "hello")
.filter(e -> e.length() > 1)
.collect(Collectors.toList());
assert list3.equals(Arrays.asList("hello"));
Student s1 = new Student();
s1.setGrade(1);
s1.setAge(17);
s1.setName("zhangsan");
s1.setScores(Arrays.asList(88, 77));
Student s2 = new Student();
s2.setGrade(1);
s2.setAge(18);
s2.setName("lisi");
s2.setScores(Arrays.asList(67, 78));
Student s3 = new Student();
s3.setGrade(2);
s3.setAge(16);
s3.setName("wangwu");
s3.setScores(Arrays.asList(80, 90));
List<Student> students = new ArrayList<>();
students.add(s1);
students.add(s2);
students.add(s3);
//flatMap:将多个Stream连接成一个Stream,而不是一连串的流;
List<Integer> scoreList = students.stream()
.flatMap(student -> student.getScores().stream())
.collect(Collectors.toList());
assert scoreList.equals(Arrays.asList(88, 77, 67, 78, 80, 90));
//max & min: 求最大值/最小值,需要传递一个Comparator对象,实现静态方法comparing,从而实现一个比较器;
int max = Stream.of(1, 2, 3).max(Comparator.comparing(e -> e)).get();
//max = Stream.of(1, 2, 3).mapToInt(e -> e).max().getAsInt();
assert max == 3;
Student min = students.stream()
.max(Comparator.comparing(e -> e.getAge()))
.get();
//int min = students.stream().mapToInt(e -> e.getAge()).min().getAsInt();
assert min.getAge() == 16;
//count: 计数
long count = Stream.of(Arrays.asList(1, 2, 3)).count();
assert count == 3;
//排序:正序Collections.sort(scoreList),倒序Collections.reverse(ascList);;
List<Integer> ascList = scoreList.stream()
.sorted()
.collect(Collectors.toList());
//求平均值,返回17.0
double averageAge = students.stream().mapToInt(Student::getAge).average().getAsDouble();
//averageAge = students.stream().collect(Collectors.averagingInt(Student::getAge));
//求总和,返回51
int totalAge = students.stream().mapToInt(Student::getAge).sum();
//totalAge = students.stream().collect(Collectors.summingInt(Student::getAge));
//数据分块,返回{false=[1, 2], true=[3, 4]}
Map<Boolean, List<Integer>> map1 = Stream.of(1, 3, 4, 2)
.collect(Collectors.partitioningBy(e -> e > 2));
//数据分组,返回{1=[java8.Student@3f91beef, java8.Student@1a6c5a9e], 2=[java8.Student@37bba400]}
Map<Integer, List<Student>> map2 = students.stream()
.collect(Collectors.groupingBy(e -> e.getGrade()));
//字符串连接,返回[11,aa,22]
String result = Stream.of("11", "aa", "22").collect(Collectors.joining(",", "[", "]"));
//返回11,aa,22
result = Stream.of("11", "aa", "22").collect(Collectors.joining(","));
//list转map(key值为姓名)
Map<String, Student> studentMap = students.stream().collect(Collectors.toMap(e -> e.getName(), e -> e));
Optional
-
为核心类库新设计的一种数据类型,用来替代null值(使用null代表值不存在的最大问题在于npe);
-
使用Optional对象的两个目的:
a、Optional对象鼓励程序员适时检查变量是否为空,以避免代码缺陷;
b、它将一个类的API中可能为空的值文档话,这笔交易实现代码要简单很多;
-
在一个值可能为空的建模情况下,使用Optional对象能替代使用null值;
其他
并发 VS. 并行
并发:两个任务共享时间段。如果一个程序要运行两个任务,并且只有一个CPU给他们分配了不同的时间片,这就是并发;
并行:两个任务在同一时间发生,比如运行在多核CPU上;