【java学习】java8新特性:stream、Lambda函数、接口的默认方法和类方法、函数式接口、Optional、DateTime

1,java.util.stream(函数式编程风格)

1)概念

Stream的操作可以串行执行或者并行执行。

优点:可读性、不可变性。

  1. 保护数据源;
    对Stream中任何元素的修改都不会导致数据源被修改,比如过滤删除流中的一个元素,再次遍历该数据源依然可以获取该元素。
  2. 只遍历一遍数据源;
    即使有多个map、filter,也只遍历一次。清晰、明了。
    惰性求值,所有的中间操作都不会真正执行,在终端操作时完成整个流水线。
    中间流页不存储任何数据。
  3. 少量数据处理时(size<1000),stream处理效率低于Iterator,但对于本来耗时就短的代码,stream可读性更高。
    大量数据(size>1w)时,stream效率远远高于iterator,尤其是使用并行流时,利用多核cpu。
  4. 并行流(parallelStream):当能分配到多个cpu核时性能很高,否则性能还不如stream(单核不推荐使用并行流)。
    parallelStream底层实现:JVM 的 ForkJoinPool。

2)流的特性

1>Intermediate

  1. 一个流可以后面跟随零个或多个 intermediate 操作。
  2. Intermediate操作是惰性化的(lazy),并没有真正开始流的遍历。
  3. 相关操作:
    map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

2>Terminal

  1. 一个流只能有一个 terminal 操作,作为流的结束操作。
  2. Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
  3. 相关操作:
    forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

3>Short-circuiting

  1. 对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
  2. 对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。
  3. 当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。
  4. 相关操作:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit.

3)流的使用

三个步骤:
语句结构聚合操作为最终操作。

1>获取一个数据源(source)

  1. 数据源包含集合、数组、I/O channel、generator(发生器)等。
  2. 创建Stream(串行执行)、parallelStream(多个线程并行执行);
功能 举例 备注
获取一个顺序流stream() 数组转流:Arrays.asList("1","2").stream()
list转流:list.stream()
map转流:aMap.entrySet().stream()
通过Collection接口的默认方法default Stream< E> stream() 获取;
获取一个并行流:parallelStream() Arrays.asList("1","2").parallelStream()
list.parallelStream()
通过Collection接口的默认方法default Stream< E> parallelStream()获取;
注意线程安全问题
常量转换为stream Stream stream = Stream.of("a", "b", "c") 通过Stream接口的静态工厂方法实现。
数据量小的情况下性能并不会特别好。
生成一个无限长度的流 Stream.generate(() -> Math.random());
Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);
一般和limit一起使用
流的合并 Stream.concat() Stream.concat(Stream.of(1, 4, 3), Stream.of(2, 5)).forEach() 1. 新的流顺序:流1+流2;
2. 并行性:两个流有一个并行则新流也是并行的;
关闭:新流关闭,原来的2个流也都关闭。

2>中间操作(转换stream)

每次转换原有的Stream对象不改变,返回一个新的Stream对象。

  1. stream 中含有装箱类型,在进行中间操作之前,最好转成对应的数值流,减少由于频繁的拆箱、装箱造成的性能损失;
功能 举例 备注
去重 distinct() 去重逻辑依赖元素的equals方法
过滤 . filter(word -> word.length() > 0) filter里面是true,表示保留
一对一转换 .map(String::toUpperCase)
.map(n -> n * n)
map转list:.map(Map.Entry::getValue)
新生成的Stream只包含转换生成的元素
一对多转换 .flatMap((childList) -> childList.stream()) 把子Stream中的元素压缩到父集合中
转换为int .mapToInt(x -> x.length())
.mapToInt(Integer::parseInt)
查看中间执行结果 peek 主要用于调试目的,通常用于查看中间操作的结果。
例如在对流进行过滤或映射前后,此时会生成一个新的流输出中间计算结果。不会影响原来steam的内容
截断 .limit(10) 用法:
1. 与skip搭配进行分页计算;
2. topN
跳过元素 skip(2) 跳过前n个元素并丢弃,返回新的stream。如果元素数量小于n,返回空stream;
.stream().skip(2).limit(2).collect(Collectors.toList())) 输入[0, 1, 2, 3, 4],输出[2, 3] 分页
排序 .sorted() 详细用法见下文 返回新的stream,不会影响原有数据源。
1>sort 排序
  1. map升序:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
  1. map降序:
map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
  1. list升序:
list.stream().sorted()...
  1. list降序:
list.stream().sorted(Comparator.reverseOrder())...
  1. List<Object>排序
.sorted(new Comparator<OrgInfo>() {
   
   
                    @Override
                    public int compare(OrgInfo o1, OrgInfo o2) {
   
   
                        //升序排序,降序反写
                        return o1.getId()-o2.getId();
                    }
                })

3>Reduce Stream(聚合操作,最终操作)

将输入元素转换为一个最终形式返回。

功能 方法 备注
归约 Optional<String> reduced = list.stream().reduce((s1, s2) -> s1 + "#" + s2) 将传入的函数作用在序列的第一个元素得到结果后,把这个结果继续与下一个元素作用(累积计算);
归约后的结果是通过Optional接口表示;
reduce接收的是BinaryOperator类型的lambada表达式
转换为list .collect(toList())
转换为set .collect(toSet())
转换为map .collect(Collectors.toMap(Task::getTitle, Function.identity(), (existing, replacement) -> existing)) Function.identity()相当于task->task
(existing, replacement) -> existing) 表示key值冲突保留之前(replace表示新值替换旧值)
对值分组为map .collect(Collectors.groupingBy(task -> task.getType()))
分割流中的元素 .collect(Collectors.partitioningBy(task -> task.getDueOn().isAfter(LocalDate.now()))) 比如将任务分割为要做和已经做完的任务
求和 Integer count = list.stream().mapToInt(Task::getCount).sum()
求最值 max和min
计数 .count()
数据匹配 allMatch:是不是Stream中的所有元素都满足给定的匹配条件;
anyMatch:Stream中是否存在任何一个元素满足匹配条件;
noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件
返回boolean值
boolean anyStartsWithA = list.stream().anyMatch((s) -> s.startsWith("a"))
返回Stream中的第一个元素 findFirst 返回Stream中的第一个元素,如果Stream为空,返回空Optional
循环 forEach 和for性能无差异;
不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环

4)其它

①流转换为其它数据结构

// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 =
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值