行为参数化是指拿出一个代码块把他准备好却不执行它。这个代码块以后可以被程序的其他部分调用,意味着你可以推迟这块代码的执行。方法接受多种行为作为参数,并在内部使用来完成不同的行为。行为参数话的好处在于可以把迭代要筛选的集合的逻辑与对集合中的每个元素应用的行为区分开来。

  Java的匿名类可以同时声明和实力化一个类。但它往往很笨重,占用了很多空间同时还不易理解。

  可以把Lambda表达式看作匿名功能,它基本上是没有声明名称的方法,但和匿名类一样,它也可以作为参数传递给一个方法。Lambda表达式可以简洁地表示可传递的匿名(Lambda不像普通方法那样有一个明确的名称)函数(Lambda函数不属于某个特定的类,但Lambda有参数列表,函数主题,返回类型和异常列表)的一种方式:它没有名称,但它有参数列表,返回类型还可能有一个可以抛出的异常列表。Lambda表达式可以作为参数传递给方法或存储在变量中,并且无需像匿名类那样写很多模板代码。

  Lambda表达式有三个部分:参数列表,箭头和Lambda主体。(parameters) -> expression 或 (parameters) -> {statements;}

  通常在函数式接口上使用Lambda表达式。函数式接口就是只定义一个抽象方法的接口。

  Lambda表达式以內联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例,具体来讲时函数式接口的一个具体实现的实例。函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,这种抽象方法称为函数描述符。()->void代表了参数列表为空且返回void的函数。函数式接口通常带有@FunctionalInterface的注解。它用于表示该接口会被设计为一个函数式接口。若定义了一个不是函数式接口但带有@FunctionalInterface的注解,编译器将报错:Multiple non-overriding abstract methods found in interface XX。

  

  java.util.function包中引入了几个新的函数式接口:

  Predicate<T>接口定义了一个名为test的抽象方法,它接受一个T对象,并返回一个boolean。通常用于一个涉及类型T的布尔表达式。

  @FunctionalInterface

  public interface Predicate<T>{

    boolean test(T t);

  }

  public static <T> List<T> filter(List<T> list, Predicate<T> p){

    List<T> results = new ArrayList<>();

    for(T t : list){

      if(p.test(t)){

        results.add(t);

      }

    }

  }

  Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

  List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

  Consumer<T>定义了一个accpet抽象方法,它接受一个T对象,没有返回。通常用于访问类型T的对象并对其执行某些操作。

  @FunctionalInterface

  public interface Consumer<T>{

    void accept(T t);

  }

  public static <T> void forEach(List<T> list, Consumer<T> c){

    for(T t : list){

      c.accpet(t);

    }

  }

  forEach(Arrays.asList(1, 2, 3, 4), (Integer i) -> System.out.println());

  Function<T, R>接口定义一个apply方法,接受一个T对象,并返回一个R对象。通常用于将输入对象的信息映射到输出。

  @FunctionalInterface

  public interfaces Function<T, R>{

    R apply(T t);

  }

  public static <T, R> List<R> map(List<T> list, Function<T, R> f){

    List<R> results = new ArrayList<>();

    for(T t : list){

      results.add(f.apply(t));

    }

    return results;

  }

  List<Integer> list = map(Arrays.asList("lambdas", "in", "action"), (String s) -> s.length());

  将一个原始类型转换为对应的引用类型的机制称为装箱。将引用类型转换为对应的原始类型称为拆箱。Java有自动装箱机制,但是会影响性能。装箱后的值本质上是把原始类型包裹起来,并保存在堆里。因此装箱后的值需要更多的内存,并需要额外的内存搜索来获取被包裹的原始值。

  通常,针对专门的输入参数类型的函数式接口的名称要加上对应的原始类型前缀,比如DoublePredicate,IntConsumer等。Function接口还有针对输出参数类型的变种:ToIntFunction<T>, IntToDoubleFunction等。

  

                      java8常用函数式接口

  函数式接口        函数描述符      原始类型特化

  Predicate<T>         T -> boolean      IntPredicate,LongPredicate,DoublePredicate

  Consumer<T>      T -> void       IntConsumer, LongConsumer, DoubleConsumer

  Function<T, R>       T -> R          IntFunction<R>, IntToDoubleFunction, IntToLongFunction,LongFunction<R>, LongToDoubleFunction, LongToIntFunction, DoubleFunction<R>, ToIntFunction<T>, ToDoubleFunction<T>, ToLongFunction<T>

  Supplier<T>         () -> T         BooleanSupplier, IntSupplier, LongSuppier, DoubleSupplier

  UnaryOperator<T>     T -> T                     IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator

  BinaryOperator<T>    (T, T) -> T        IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator

  BiPredicate<L, R>    (L, R) -> boolean  

  BiConsumer<T, U>   (T, U) -> void     ObjIntConsumer<T>, ObjLongConsumer<T>, ObjDoubleConsumer<T>

  BiFunction<T, U, R>   (T, U) -> R     ToIntBiFunction<T, U>, ToLongBiFunction<T, U>, ToDoubleBiFunction<T, U>

  

  任何函数式接口都不允许抛出受检查异常。若需要Lambda表达式来抛出异常,有两种方l法,一种是定义一个自己的函数式接口,并声明受检查异常,另一种是把Lambda放到一个try-catch块中。

  Lambda的类型是从使用Lambda的上下文推断出来的。上下文中Lambda表达式需要的类型称为目标类型。若Lambda的主体是语句表达式,它就和一个返回void的函数描述符兼容。

  Lambda可以使用自有变量,它们被称为捕获Lambda。Lambda可以没有限制地捕获实例变量和静态变量。但局部变量必须显式的声明为final或事实上就是final。因为Lambda表达式只能捕获指派给它们的局部变量一次,实例变量可以看作捕获最终局部变量this。

  闭包是一个函数的实例,且它可以无限制地访问哪个函数的非本地变量。

  方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。它的基本思想是若一个Lambda代表的只是直接调用这个方法,最好还是用名称来调用它,而不是去描述如何调用它。方法的引用实际上就是根据已有的方法实现来创建Lambda表达式。使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。方法的名称不需要括号,因为并么有实际调用这个方法。

  方法引用主要有三类

    1.指向静态方法的方法引用,如Integer::parseInt

    2.指向任意类型实例方法的方法引用,如String::length

    3.指向现有对象的实例方法的引用,如obja::methodName

  对于构造函数,利用它的名字和关键字new来创建它的一个引用。ClassName::new。若是无参的构造函数,() -> ClassName更适合。  

  Comparator具有一个叫comparing的静态辅助方法,它接受一个Function来提取Comparable健值,并声称一个Comparator对象。

  inventory.sort(comparing( (a) -> a.getWeight()));

  把多个简单的Lambda复合成复杂的表达式。如两个谓词之间做个or操作或让另一个函数的结果变为另一个函数的输出。

  可以通过reversed间给定的比较器逆序。inventory.sort(comparing((a) -> a.getWeight()).reversed());

  thenComparing接受一个函数作为参数,若两个对象用第一个Comparator比较后是一样的,则提供第二Comparator。

  inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry));

  

  谓语接口包括三个方法:negate,and和or。

  negate方法用来返回一个Predicate的非。

  Predicate<Apple> notRedApple = redApple.negate();

  and和or可以将两个Lambda表达式组合起来。and和or方法是按照在表达式链中的位置,从左到右确定优先级的

  Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor()));

  

  Function中有andThen和compose两个默认方法,他们都会返回一个Function实例。

  andThen方法会返回一个函数,它先对输入应用过一个给定函数,在对输出应用另一个函数。

  Function<Integer, Integer> f = x -> x + 1;

  Function<Integer, Integer> g = x -> x * 2;

  Function<Integer, Integer> h = f.andThen(g);

  int result = h.apply(1); // g(f(x))

  h = f.compose(g);

  result = h.apply(1); // f(g(x));

行为参数化和Lambda表达式的更多相关文章

  1. 行为参数化与lambda表达式 - 读《Java 8实战》

    零. 概述 第一部分:1~3章 主要讲了行为参数化和Lambda表达式 第二部分:4~7章 主要讲了流的应用,包括流与集合差异,流的操作,收集器,注的并行执行 第三部分:8~12章 主要讲了怎样用Ja ...

  2. Java8新特性之Lambda表达式

    lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...

  3. Java 8新特性(一):Lambda表达式

    2014年3月发布的Java 8,有可能是Java版本更新中变化最大的一次.新的Java 8为开发者带来了许多重量级的新特性,包括Lambda表达式,流式数据处理,新的Optional类,新的日期和时 ...

  4. 一篇文章教会你使用Java8中的Lambda表达式

    简介 Java 8为开发者带来了许多重量级的新特性,包括Lambda表达式,流式数据处理,新的Optional类,新的日期和时间API等.这些新特性给Java开发者带来了福音,特别是Lambda表达式 ...

  5. JAVA8 in Action:行为参数化,匿名类及lambda表达式的初步认知实例整理

    import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.functio ...

  6. 如何优雅的将文件转换为字符串(环绕执行模式&行为参数化&函数式接口|Lambda表达式)

    首先我们讲几个概念: 环绕执行模式: 简单的讲,就是对于OI,JDBC等类似资源,在用完之后需要关闭的,资源处理时常见的一个模式是打开一个资源,做一些处理,然后关闭资源,这个设置和清理阶段类似,并且会 ...

  7. Upgrading to Java 8——第一章 Lambda表达式

    第一章 Lambda表达式 Lamada 表达式是Java SE 8中最重要的新特性,长期以来被认为是在Java中缺失的特性,它的出现使整个java 语言变得完整.至少到目前,在这节中你将学习到什么是 ...

  8. LINQ(隐式表达式、lambda 表达式)

    .NET 中一项突破性的创新是 LINQ(Language Integrated Query,语言集成查询),这组语言扩展让你能够不必离开舒适的 C# 语言执行查询. LINQ 定义了用于构建查询表达 ...

  9. Java8学习(3)- Lambda 表达式

    猪脚:以下内容参考<Java 8 in Action> 本次学习内容: Lambda 基本模式 环绕执行模式 函数式接口,类型推断 方法引用 Lambda 复合 上一篇Java8学习(2) ...

随机推荐

  1. PyCharm + PyQt4 环境搭建

    一.准备工作 下载pycharm 和 pyqt4 (百度下就有) pyqt4安装好后,在C:\Python27\Lib\site-packages\PyQt4 路径下会有designer.exe ,这 ...

  2. PAT 1050 String Subtraction

    1050 String Subtraction (20 分)   Given two strings S​1​​ and S​2​​, S=S​1​​−S​2​​ is defined to be t ...

  3. visual studio利用 indent guides 格式化代码 添加竖线

    点击 Visual Studio 2013 工具—扩展和更新—联机 然后输入indent guides 自动搜索出来这个插件(如图).注:Visual Studio 2010需要自己在网上下载安装. ...

  4. 【LeetCode】大数相乘

    1. 模拟手工计算 原理: 将 string 反转存储在 int 数组中,如 A = 17 = (7, 1),B = 25 = (5, 2),亦即幂表示法,幂次是从低位到高位. 作逐位相乘,即 ai ...

  5. https 不会被中间人攻击——因为中间人即使拿到了数据,也是加密的

    只要你登陆了一个使用 HTTPS 数据加密的网站,浏览的页面的内容如果被人中途看见,将会是一团乱码.它也能保证,你浏览的页面就是你想浏览的,不会被黑客在中途修改,网站收到的数据包也是你最初发的那个,不 ...

  6. python列表反转函数

    def reverse(ListInput): RevList=[] for i in range (len(ListInput)): RevList.append(ListInput.pop()) ...

  7. 把旧系统迁移到.Net Core 2.0 日记(1) - Startup.cs 解析

    因为自己到开发电脑转到Mac Air,之前的Webform/MVC应用在Mac 跑不起来,而且.Net Core 2.0 已经比较稳定了. 1. 为什么会有跨平台的.Net Core  近年来,我们已 ...

  8. Spring之缓存注解@Cacheable

    https://www.cnblogs.com/fashflying/p/6908028.html https://blog.csdn.net/syani/article/details/522399 ...

  9. ACCESS数据库基本使用

    ACCESS是Office自带的数据库,使用起来非常方便. 相比,其它数据库来说,使用率较低,但是同MYSQL一样,免费.正因为如此,所以很多建站的程序员,还是会选择使用它. 部分代码: <sc ...

  10. puppeteer 爬虫 pdf 截图 自动化

    puppeteer简介 puppeteer 翻译是操纵木偶的人,利用这个工具,我们能做一个操纵页面的人.puppeteer是一个nodejs的库,支持调用Chrome的API来操纵Web,相比较Sel ...