java8新特性之Lambda与Stream流

Lambda表达式

使用Lambda表达式需要注意一下两点:

  • lambda表达式主要用来执行行内执行的方法类型的接口,该接口内只能有一个抽象方法。可以定义静态方法和默认方法,也允许有Object类中的public方法
  • lambda表达式当中不允许声明一个与局部变量参数同名的参数或是局部变量。
  • lambda表达式免去了使用匿名方法的麻烦,并且给与了java简单但是强大的函数化的编程能力

@FunctionalInterface:修饰函数式接口的,要求接口中的抽象方法只有一个。 这个注解往往会和 lambda 表达式一起出现。如果该接口加了本注解,却不符合函数式编程的条件,那么编译器便会报错。Java 8的java.util.function包下定义了很多借口,都是用来方便书写lambda表达式的

接口增加方法,所有实现类都要在实现类里重写这个新增的方法,这样就会很麻烦;
jdk8 为接口新增了default 修饰的方法(默认方法必须有实现体),而且可以有方法体,这样所有的实现类就都有了这个方法,子类如果需要重写也是可以的;默认方法时可以有多个的。也可以在接口中定义静态方法。

方法引用

Consumer<String> consumer = System.out::println;
consumer.accept("唐芬");

方法引用方法的参数列表必须与函数式接口的抽象方法的参数列表保持一致,返回值不作要求。
方法引用调用的方法时某个对象的某个方法(就一个方法)。

引用方法使用:

实例对象::实例方法名
类名::静态方法名
类名::实例方法名

引用的方法可以是:

  • 引用方法
  • 引用构造方法
  • 引用数组

Function<Integer,int[]> function = int[]::new;
function.apply(10);

Optional

Stream:

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的Iterator,可以看成管道。

  1. Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
  2. Stream 就如同一个Iterator,单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。
  3. Stream 可以并行化操作,Iterator只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架来拆分任务和加速处理过程。

Stream的操作类型

  • 中间操作(Intermediate Operation):一个流可以后面跟随零个或多个 intermediate操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
  • 终止操作(Terminal Operation):一个流只能有一个 terminal操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果。

Intermediate Operation又可以分为两种类型:

  • 无状态操作(Stateless Operation):操作是无状态的,不需要知道集合中其他元素的状态,每个元素之间是相互独立的,比如map()、filter()等操作。
  • 有状态操作(Stateful Operation):有状态操作,操作是需要知道集合中其他元素的状态才能进行的,比如sort()、distinct()。

Terminal Operation从逻辑上可以分为两种:

  • 短路操作(short-circuiting):短路操作是指不需要处理完所有元素即可结束整个过程
  • 非短路操作(non-short-circuiting):非短路操作是需要处理完所有元素之后才能结束整个过程

Filter:
filter 对原始 Stream 进行某项过滤测试,通过过滤测试的元素被留下来生成一个新 Stream。

Integer[] nums = new Integer[]{1,2,3,4,5,6};
Arrays.stream(nums).filter(n -> n<3).forEach(System.out::println);

ForEach:
forEach 是 terminal 操作,因此它执行后,Stream 的元素就被“消费”掉了,你无法对一个 Stream 进行两次terminal 运算,forEach 不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环
相反,具有相似功能的 intermediate 操作 peek 可以达到上述目的。

redure:
这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个…第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce.例如 Stream 的 sum 就相当于:

Integer[] nums = new Integer[]{1,2,3,4,5,6};
Integer sum = Arrays.stream(nums).reduce(0, (integer, integer2) ->
integer+integer2);
System.out.println(sum);

Limit/Skip
limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素.

Integer[] nums = new Integer[]{1,2,3,4,5,6};
Arrays.stream(nums).limit(3).forEach(System.out::print);
System.out.println();
Arrays.stream(nums).skip(2).forEach(System.out::print);   

输出结果为

123
3456

sorted:
对 Stream 的排序通过 sorted 进行,它比数组的排序更强之处在于你可以首先对 Stream 进行各类 map、filter、limit、skip 甚至 distinct 来减少元素数量后,再排序,这能帮助程序明显缩短执行时间。

min/max/distinct

Integer[] nums = new Integer[]{1, 2, 2, 3, 4, 5, 5, 6};
System.out.println(Arrays.stream(nums).min(Comparator.naturalOrder()).get());
System.out.println(Arrays.stream(nums).max(Comparator.naturalOrder()).get());
Arrays.stream(nums).distinct().forEach(System.out::print);

输出

1
6 最大元素6
6 不重复元素个数

Stream 有三个 match 方法,从语义上说:
allMatch:Stream 中全部元素符合传入的 predicate,返回 true
anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
它们都不是要遍历全部元素才能返回结果。例如 allMatch 只要一个元素不满足条件,就 skip 剩下的所有元素,返回 false。

Collectors来进行reduction操作
java.util.stream.Collectors 类的主要作用就是辅助进行各类有用的 reduction 操作,例如转变输出为 Collection,把 Stream 元素进行归组。
groupingBy/partitioningBy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值