# Java8-Lambda
# 一、Lambda表达式
基本格式:
(参数列表) -> {方法体}
Stream流,结合Lambda提供了对集合的流水线操作,使得代码具有非常高的可读性,优雅性!
- Stream提供了对集合的便捷化处理方式
- 声明式编程的思想
- lambda只能简化函数式接口(接口中,有且只有一个抽象方法)
- Lambda使得代码更加优雅,简洁,不信你往下看→_→
# 1.1 函数式接口
Java内置的函数式接口 java.util.function 包下,常见的如下:
项目 | 描述 | 备注 |
---|---|---|
Consumer<T> | void accept(T t) | 消费型接口,无返回值仅消费参数 |
Function<T, R> | R apply(T t) | 计算转换类,将参数转换为其他对象返回 |
Predicate<T> | boolean test(T t) | 参数进行条件判断 |
Supplier<T> | T get() | 生产型接口,返回一个对象 |
# 二、Stream基础和操作
# 2.1 Stream相关概念
Stream的所有操作分为三个阶段,【创建】>> 【中间操作】>> 【终端操作】
注意:创建的默认都是串行流,可以通过
parallel()
改成并行流
1.创建
//直接通过指定的元素创建
Stream<String> stream = Stream.of("1", "2", "3");
//通过list构建
List<String> list = Arrays.asList("1", "2", "3");
Stream<String> stream = list.stream();
//数组构建
Integer[] arr = {1,2,3,4}
Stream<Integer> stream = Arrays.stream(arr);
//Map
Map<String, Object> map = new HashMap<>();
Stream<Map.Entry<String, Object>> stream = map.entrySet().stream();
2
3
4
5
6
7
8
9
10
11
2.中间操作
Stream Operation | Goal | Input |
---|---|---|
filter | filter 方法用于通过设置的条件过滤出元素。 | 条件(返回布尔值)Predicate |
map | map 方法用于映射每个元素到对应的结果 | 可以是一个功能 Function |
skip | skip(5) 跳过5个元素 | long值 |
limit | limit(5) 方法用于获取5个元素 | long值 |
sorted | sorted 方法用于对流进行排序 | Comparator |
distinct | 去除重复(注意要重写equals和hashcode) | -- |
parallel | parallelStream 是流并行处理程序的代替方法 | -- |
例子
Random random = new Random();
random.ints(0, 10).limit(5).map(i -> (i * i)).distinct().sorted().forEach(System.out::println);
//根据属性名排序,比如创建时间
List<Student> stuList = studentList.stream().sorted((s1, s2) -> s2.getAge() - s1.getAge()).collect(Collectors.toList());
List<Student> stuList = studentList.stream().sorted(Comparator.comparing(Student::getCreateTime)).collect(Collectors.toList());
2
3
4
5
3.终端操作
Stream Operation | Goal | Input Or Output |
---|---|---|
forEach | 遍历元素 | 其他操作 |
count | 统计元素个数 | -- |
collect | 聚合操作 | -- |
# 2.2 collect聚合
Collectors
提供了一系列的静态方法供我们使用,toList/toSet/toMap/toCollection/toConcurrentMap
- 转List或者Set
// ArrayList
List<Integer> stuIds = studentList.stream().map(Student::getId).collect(Collectors.toList());
//HashSet
Set<Integer> stuIds = studentList.stream().map(Student::getId).collect(Collectors.toSet());
2
3
4
要转LinkedList类型,或者TreeSet等其他类型,用 toCollection
//LinkedList
List<Integer> stuIds = studentList.stream().map(Student::getId).collect(Collectors.toCollection(LinkedList::new));
2
- 转Map
有重复的数据,会报错 duplicateKeyException,解决办法,在toMap中添加第三个参数mergeFunction,
(o1, o2) -> o1
即 如果有重复的key,则保留key1,舍弃key2 来解决冲突的问题
Map<Integer, Student> stuMap = studentList.stream().collect(Collectors.toMap(Student::getId, Function.identity()));
//解决重复key
Map<Integer, Student> stuMap = studentList.stream().collect(Collectors.toMap(Student::getId, Function.identity(), (o1, o2) -> o1));
2
3
- collectingAndThen
先进行结果集的收集,然后将收集到的结果集进行下一步的处理
先归纳处理Collectors.toCollection()转成TreeSet集合,用到这个
() -> new TreeSet<>(Comparator.comparing(Student::getName)))
策略,即把Student放到TreeSet根据名称去重,再交给 FunctionR apply(T t),也就是将结果设置成t
处理,即创建ArrayList<Student>(TreeSet)
返回
//根据学生姓名去重,这里看起来笔记复杂,拆开看
List<Student> stu = studentList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getName))), ArrayList::new));
2
3
- joining
Joining用来以某种规则连接stream中的元素,三种重载
joining()
joining(CharSequence delimiter)
joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix)
List<String> list = Arrays.asList("Tomcat", "Jetty", "Nginx");
//TomcatJettyNginx
list.stream().collect(Collectors.joining());
//Tomcat Jetty Nginx
list.stream().collect(Collectors.joining(" "));
//[Tomcat,Jetty,Nginx]
list.stream().collect(Collectors.joining(",", "[", "]"));
2
3
4
5
6
7
- 统计
Collectors.counting
用来统计stream中元素的个数Collectors.summingDouble/Long/Int
对stream中的元素做sum操作Collectors.maxBy/minBy
根据提供的Comparator,返回最大或者最小值Collectors.summarizingDouble/Long/Int
统计类,对以上三个做统计整合
- 分组
Collectors.groupingBy
根据某些属性进行分组,并返回 HashMap(原来集合里的数据顺序会打乱重排列)
Map<Integer, List<Student>> group = studentList.stream().collect(Collectors.groupingBy(Student::getStudentNo));
//解决办法,使用LinkedHashMap分组按之前List的顺序
Map<Integer, List<Student>> group = studentList.stream().collect(Collectors.groupingBy(Student::getStudentNo, LinkedHashMap::new, Collectors.toList()));
2
3
考虑线程安全,下面或者groupingByConcurrent
Supplier<Map<Integer, Set<String>>> mapSupplier = () -> Collections.synchronizedMap(new HashMap<>());
Map<Integer, Set<String>> collect = servers.stream.collect(Collectors.groupingBy(String::length, mapSupplier, Collectors.toSet()));
2
实测例子
public static void main(String[] args) {
List<String> lists = new ArrayList<String>() {{
add("A");
add("D");
add("C");
add("B");
add("A");
}};
System.out.println("原始列表数据 :" + lists);
Map<String, List<String>> collect1 = lists.stream().collect(Collectors.groupingBy(x -> x));
System.out.println("JAVA Stream分组处理完,默认处理:" + collect1);
Map<String, List<String>> collect = lists.stream().collect(Collectors.groupingBy(x -> x, LinkedHashMap::new, Collectors.toList()));
System.out.println("JAVA Stream分组处理完,LinkedHashMap:" + collect);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- Collectors.mapping
先对元素使用 Function 进行再加工操作,然后用另一个Collector 归纳
strList.stream.collect(Collectors.mapping(s -> s.substring(1), Collectors.toList()));
- Collectors.reducing
元素两两之间进行比较根据策略淘汰一个,随着轮次的进行元素个数就是 reduce 的
# 2.3 Optional
可以为null的容器对象,Optional可以很方便的帮助我们来解决NPE的问题
- orElseThrow
- orElseGet
如下代码,判空头皮发麻吧,手动狗头
public static void main(String[] args) {
Student student = getStudent();
if (null != student) {
Address address = student.getAddress();
if (null != address) {
Province province = address.getProvince();
if (null != province) {
System.out.println(province.getName());
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
接下来看神奇操作,秀不秀
String name = Optional.ofNullable(getStudent())
.map(o -> o.getAddress())
.map(o -> o.getProvince())
.map(o -> o.getName())
.orElseThrow(NullPointerException::new);
2
3
4
5