第七章 函数接口,lambda和方法引用

java8 函数接口,lambda和方法引用

第四十二条, lambda 优先于匿名类(lambda表达式)
1.函数接口,带有单个抽象方法的接口
2.匿名对象,创建函数对象,会很繁琐

  //匿名函数创建函数对象实例
  Collections.sort(new ArrayList<String>(), new Comparator<String>() {
      @Override
      public int compare(String o1, String o2) {
          return Integer.compare(o1.length(),o2.length());
      }
  });

3.java8中带有单个抽象方法的接口是特殊的,值得特殊对待的观念,这些接口现在被称为函数接口,java允许使用
lambda表达式创建这些就接口是实例

  //lambda表达式创建函数接口
  Collections.sort(new ArrayList<String>(),(x,y)->Integer.compare(x.length(),y.length()));

4.java是通过复杂的上下文推导出x,y的类型,以及返回类型和int。删除所有lambda参数的类型吧,除非他们的存在
能够使程序更加清晰,如果编译器产生一个错误的消息,告诉你无法推导的参数类型,那么你就指定类型,使用
泛型才更好的推导
5.DoubleBinaryOperator接口,带有两个double类型的参数,返回一个double类型的结果
6.lambda表达式没有名称和文档,如果一个计算本身不是自描述得,或超出了几行,那就不要把它放到一个lambda
表达式中,一行最理想,三行最大极限,如果违背这一条,可能导致程序的可读性不好
7.lambda表达式的this指的是外外围对象而不是自身,匿名函数的this指的就是匿名实例本身
8.lambda与匿名类共享你无法可靠地通过实现序列化和反序列化的属性,因此,尽可能不要(除非迫不得已)序列化
一个lambda或者匿名类,如果需要可序列化的函数对象。就使用静态嵌套类的实例
9.千万不要给函数对象使用匿名类,除非必须创建非函数接口的类型的实例

第四十三条,方法引用优先于lambda
1.实例

  //lambda
  map.merge(key,(count,incr)->count+incr)
  //方法引用,Integer在java8中增加了求两个数的和的静态方法sum,这里直接方法引用即可
  map.merge(key,Integer::sum)

2.只要方法引用可以做的事,就没有lambda做不到的(只有一种例外,JLS 9.9-2)
3.许多方法引用都会引用静态方法,但有4种方法引用不会引用静态方法
1.有限制的实例方法引用,函数对象与被引用方法带有相同的参数;
Instant.now()::isAfter Instant than = Instant.now(); t -> than.isAfter(t);
2.无限制的实例方法引用,接收对象是在运用函数对象时,通过在该方法的声明函数前面额外添加一个参数来
指定,经常用在流管道;String::toLowerCase str->str.toLowerCase()
3.类构造器;TreeMap<K,V>::new ()->new TreeMap<K,V>
4.数组构造器;int[]::new len->new int[len]
5.静态;Integer::parseInt str->Integer.parseInt(str)
4.只要方法引用更加简洁,清晰,就使用方法引用,如果方法引用并不简洁,就坚持使用lambda

第四十四条,坚持使用标准的函数接口
1.只要标准的函数接口能够满足需求,通常应该优先考虑,而不是专门在构建一个新的函数接口
1.UnaryOperator<T> T apply(T y) String::toLowerCase
2.BinaryOperator<T> T apply(T t1,T t2) BigInteger::add
3.predicate<T> boolean test(T t) Collection::isEmpty
4.Supplier<T> T get() Instant::now
5.Consumer<T> void accept(T t) System.out::println
6.Function<T,R> R apply(T t) Arrays::asList
这6个接口,每一个都有3种变体,分别作用于 int long double基本数据类型的,比如IntPredicate,LongUnaryOperator等,这
些参数都不能参数化(泛型)
2.Function<int[]>,它的参数化类型代表的是返回值的类型,Function接口有9个变种
LongToDoubleFunction LongToIntFunction
IntToDoubleFunction IntToLongFunction
DoubleToIntFunction DoubleToLongFunction
Function<T, U>有3个变体,返回 int long double基本数据类型
ToDoubleFunction ToIntFunction ToLongFunction
3.接收两个参数的变体
BiPredicate<T, U> BiFunction<T, U, R> BiConsumer<T, U>
BiFunction<T, U, R>有3个变体,返回 int long double基本数据类型
ToIntBiFunction<T, U> ToDoubleBiFunction<T, U> ToLongBiFunction<T, U>
Consumer接口的两个参数的变体,一个是对象,一个是基本数据类型
ObjDoubleConsumer<T> ObjIntConsumer<T> ObjLongConsumer<T>

4.BooleanSupplier 返回Boolean类型的Supplier

5.千万不要用带包装类型的基础函数接口代替基本函数接口
6.编写自己的函数接口的条件
1.通用,并且将受益于描述性的名称
2.具有与其关联的严格的契约
3.将受益于定制的缺省方法
6.必须始终用@FunctionInterface注解对自己编写的函数接口进行标注
7.编写方法时,不要编写在同一个参数位置使用不同的函数接口的重载,比如ExecutorService.submit()就可以接收
Runnable和Callable,但是Callable却是Runnable的子类,如果Runnable数组里面,既有Runnable和Callable,那么就可能执行
Runnable而不执行Callable的submit,防止编写这样的客户端,可以参考52条建议

第四十五条,谨慎使用Stream
1.stream代表数据元素有限或无限的顺序,stream pipeline则代表这些元素的一个多级计算
2.stream pipeline通常是lazy的,等待终止操作时才会计算,所以千万不要忘了终止操作
3.默认情况下stream pipeline是按顺序执行的,也可以并发只要在stream pipeline中调用parallel()方法,一般不建议这么做(48)
4.在没有显式类型的情况下,仔细命名lambda参数,这对于stream pipeline 的可读性至关重要
5.在stream pipeline 中使用helper方法,对于可读性而然,比在迭代化代码中使用更为重要
6.避免使用stream来处理char,因为"LWH".chars(),实际上是一个int数组
7.重构现有的代码使用stream,并并且只在必要的时候才在新代码中使用
8.只能通过代码块,而不能通过函数对象来完成的场景
1.从代码块中,可以读取或者修改范围内的任意局部变量;从lambda则只能读取final或者有效的final变量,并且不能
修改任何local变量
2.从代码块中,可以从外围方法中return,break,continue外围循环,或者抛出该方法声明的任何受检异常,而lambda则
完全无法完成这些事情
9.通过函数对象来完成的场景
1.统一转换元素的序列
2.过滤元素的序列
3.利用单个操作(比如添加,链接和计算其最小值)合并元素顺序
4.将元素的序列存放到一个集合中,比如根据某些公共属性进行分组
5.搜索满足某些条件的元素的序列
6.如果实在不确定用steam还是用迭代比较更好,那么就两种都试试,看看哪一种更好

第四十六条,优先选择Stream中无副作用的函数
1.foreach操作应该只用于报告Stream计算的结果,而不是执行计算
2.静态导入collectors的所有成员是惯例也是明智的,因为这样可以提升Stream pipeline的可读性
3.学习collectors接口stream().collect(Collector)

第四十七条,collection要优先用Stream作为返回类型
1.当使用Stream作为返回值,因为Stream没有实现Iterator,所以无法使用foreach进行遍历
2.如果可以返回集合那就使用集合
3.看例子

      public static void main(String[] args){
          final Iterable<ProcessHandle> iterator =iterableOf(ProcessHandle.allProcesses());
          for (ProcessHandle processHandle : iterator) {
              System.out.println(processHandle.pid());
          }
      }
      //Stream->Iterable
      public static <E> Iterable<E> iterableOf(Stream<E> stream){
         // return ()->stream.iterator();
          return stream::iterator;
      }

      //Iterable->Stream
      public static <E> Stream<E> iterableOf(Iterable<E> iterable){
          // return ()->stream.iterator();
          return StreamSupport.stream(iterable.spliterator(),false);
      }
  1. IntStream.range().mapToObj()

第四十八条,谨慎使用stream并行
1.如果源头来自Stream.iterate,或者使用了中间操作的limit,那么并行pipeline也不可能提升性能,甚至可能更耗性能,
所以千万不要随意地并行Stream pipeline
2.在Stream上通过并行获得性能,最好通过ArrayList,HashMap,HashSet,ConcurrentHashMap实例,组数,int范围和long范围,
因为这些数据结构的共性是,都可以被精确,轻松的分成任意大小的子范围,使并行线程中的分工变得更加轻松
3.Stream类库用来执行这个任务的抽象是分割迭代器,他是由stream和iterable中spliterator方法返回的
4.基本数据类型数组,数组的本身是相邻的保存在内存中的,所以并行操作将会很快
5.并行Stream不仅可能降低性能,包括活性失败,还可能导致结果出错,以及难以预计的行为
6.程序中所有的并行Stream Pipeline都是在一个通用的fork-join池中运行的,只要一个pipeline运行异常,都会损害系统
中其他不相关部份的性能
7.在适当的条件下,给Stream Pipeline添加parallel调用,确实可以在多个处理器核的情况下实现近乎线性的倍增
8.并行一个随机数的Stream,使用SplittableRandom实例开始,它比TreadLocalRandom快

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容