粗略的概括:lambda表达式主要用来实现“函数接口”中“唯一”的抽象方法用的。

      他的特殊版有 方法引用,构造函数引用,用对应的接口实例接收即可。

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式 它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

  • 匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
  • 函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样, Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
  • 传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
  • 简洁——无需像匿名类那样写很多模板代码。

lambda表达式的5种方式

public void process(Runnable r){
r.run();
}
process(() -> System.out.println("This is awesome!!"));

为什么只有在需要函数式接口的时候才可以传递Lambda呢?

函数式接口

函数式接口就是只定义一个抽象方法的接口;哪怕有很多默认方法,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。

一般来说最好用@FunctionalInterface 注解标注一下。

在哪里可以使用Lambda

第三个例子的Predicate接口的定义如下:

public interface Predicate<T>{
boolean test (T t);
}

 环绕模式没看懂

通用函数式接口

Predicate、 Consumer和Function

  1. java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。

    Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
    List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
  2. java.util.function.Consumer<T>定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void) 。
  3. java.util.function.Function<T, R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。

泛型的一个坑

1.Java类型要么是引用类型(比如Byte、 Integer、 Object、 List) ,要么是原始类型(比如int、 double、 byte、 char)。但是泛型(比如Consumer<T>中的T)只能绑定到引用类型。

2.原始类型也是可以使用的,但是会在内部被封装为引用类型---作者强调---

这在性能方面是要付出代价的。装箱后的值本质上就是把原始类型包裹起来,并保存在堆里。因此,装箱后的值需要更多的内存,并需要额外的内存搜索来获取被包裹的原始值。 

所以针对专门的输入参数类型的函数式接口的名称都要加上对应的原始类型前缀,接口如下:

总结关于函数式接口和Lambda的使用案例、 Lambda的例子,以及可以使用的函数式接口。

Lambda,还有函数式接口 的异常处理

@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;//接口中抛出异常
}
//接口无法抛出的,try catch 包裹
Function<BufferedReader, String> f = (BufferedReader b) -> {
  try {
    return b.readLine();
   }
  catch(IOException e) {
    throw new RuntimeException(e);
   }
};

 困惑

当我们第一次提到Lambda表达式时,说它可以为函数式接口生成一个实例。然而, Lambda表达式本身并不包含它在实现哪个函数式接口的信息。为了全面了解Lambda表达式,你应该知道Lambda的实际类型是什么。

类型检查、类型推断以及限制 

有了目标类型的概念,同一个Lambda表达式就可以与不同的函数式接口联系起来,只要它们的抽象方法签名能够兼容。比如,前面提到的Callable和PrivilegedAction,这两个接口都代表着什么也不接受且返回一个泛型T的函数。 因此,下面的赋值是有效的: 

Callable<Integer> c = () -> 42;
PrivilegedAction<Integer> p = () -> 42; Comparator<Apple> c1 =
   (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
ToIntBiFunction<Apple, Apple> c2 =
  (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
BiFunction<Apple, Apple, Integer> c3 =
  (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

所以需要从赋值的上下文、方法调用的上下文(参数和返回值) 来判断lambda表达式。

类型推断

Comparator<Apple> c =
  (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
Comparator<Apple> c =
  (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());
//有时候显式写出类型更易读,有时候去掉它们更易读。 这两种都可以编译。
List<Apple> greenApples =
  filter(inventory, a -> "green".equals(a.getColor()));
//当Lambda仅有一个类型需要推断的参数时,参数名称两边的括号也可以省略。

局部变量的限制(懵懂)

下面的代码无法编译
错误: Lambda表达式引用的局部变量必须是最终的( final)或事实上最终的

int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber);
portNumber = 31337;

原书中是这样描述的

方法引用

方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。

当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。例如,Apple::getWeight就是引用了Apple类中定义的方法getWeight。请记住,不需要括号,因为你没有实际调用这个方法。方法引用就是Lambda表达式(Apple a) -> a.getWeight()的快捷写法。

方法引用主要有三类。

  1.指向静态方法的方法引用

    (例如Integer的parseInt方法,写作Integer::parseInt)

  2.指 向 任 意 类 型 实 例 方 法 的 方 法 引 用

    ( 例 如 String 的 length 方 法 , 写 作String::length)

  3.指向现有对象的实例方法的方法引用

  (假设你有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensiveTransaction::getValue)。

将lambda表达式重构为等价的方法引用

List<String> str = Arrays.asList("a","b","A","B");
str.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
//等价与
List<String> str = Arrays.asList("a","b","A","B");
str.sort(String::compareToIgnoreCase);

 构造函数引用

如果就new 一个对象感觉这样有点啰嗦,如果new多个对象,确实省点代码。

构造函数引用的例子:

---------------------------------------------------------------------------------------------------------------------------------

看个例子:

需求--用不同的排序策略给一个Apple列表排序

//第一版正常java代码:
public class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator()); //inventory是一个List的实例,下同 //第二版 匿名内部类
inventory.sort(new Comparator<Apple>() {
  public int compare(Apple a1, Apple a2){
    return a1.getWeight().compareTo(a2.getWeight());
  }
});

//第三版 lambda表达式
inventory.sort((Apple a1, Apple a2)-> a1.getWeight().compareTo(a2.getWeight()));
或者
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
或者
Comparator具有一个叫作comparing的静态辅助方法,它可以接受一个Function来提取Comparable键值,并生成一个Comparator对象(接口的静态方法)
Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());
现在你可以把代码再改得紧凑一点了:
import static java.util.Comparator.comparing;
inventory.sort(comparing((a) -> a.getWeight())); //第四版(最终版)
import static java.util.Comparator.comparing;
inventory.sort(comparing(Apple::getWeight));

---------------------------------------------------------------------------------------------------------------------------------

复合Lambda表达式

比较器复合 --Comparator.comparing 的内置方法

inventory.sort(comparing(Apple::getWeight) //comparing reversed thenComparing 方法返回仍然是Comparator所以可以继续调用内置方法 
  .reversed()
  .thenComparing(Apple::getCountry));

谓词复合 --Predicate 接口自带的 and or negate isEqual方法

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

函数复合 --Function接口的andThen和compose两个默认方法 

Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
//先加1在乘2
Function<Integer, Integer> h = f.andThen(g);  数学上会写作g(f(x))
//先乘2在加1
Function<Integer, Integer> h = f.compose(g); 数学上会写作f(g(x))
int result = h.apply(1);

 

java 8 学习二(Lambda表达式)的更多相关文章

  1. Java 8学习之Lambda表达式

    一.lambda表达式 一个lambda表达式包含三个部分: 一段代码 参数 自由变量的值,这里的自由指的是哪些不是参数并且没有在代码中定义的变量. 示例: public static void re ...

  2. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  3. Java8学习笔记----Lambda表达式 (转)

    Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家       本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...

  4. Lambda(二)lambda表达式使用

    Lambda(二)lambda表达式使用 Lambda 表达式组成: /* param list arrow lambda body (o1,o2) -> o1.getColor().Compa ...

  5. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

  6. Java核心技术-接口、lambda表达式与内部类

    本章将主要介绍: 接口技术:主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口. lambda表达式:这是一种表示可以在将来的某个时间点执行的代码块的简洁方法. 内 ...

  7. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  8. java函数式编程之lambda表达式

    作为比较老牌的面向对象的编程语言java,在对函数式编程的支持上一直不温不火. 认为面向对象式编程就应该纯粹的面向对象,于是经常看到这样的写法:如果你想写一个方法,那么就必须把它放到一个类里面,然后n ...

  9. 最全最强 Java 8 - 函数编程(lambda表达式)

    Java 8 - 函数编程(lambda表达式) 我们关心的是如何写出好代码,而不是符合函数编程风格的代码. @pdai Java 8 - 函数编程(lambda表达式) 简介 lambda表达式 分 ...

  10. Java 8:掌握 Lambda 表达式

    本文将介绍 Java 8 新增的 Lambda 表达式,包括 Lambda 表达式的常见用法以及方法引用的用法,并对 Lambda 表达式的原理进行分析,最后对 Lambda 表达式的优缺点进行一个总 ...

随机推荐

  1. 分布式事物解决方案-TCC

    分布式框架下,如何保证事物一致性一直是一个热门话题.当然事物一致性解决方案有很多种(请参考:分布式事物一致性设计思路),我们今天主要介绍TCC方案解决的思路.以下是参与设计讨论的一种解决思路,大家有问 ...

  2. springmvc单例

    默认情况下springmvc都是单例的,用@Controller注解的web页面,下次请求时,可以拿到controller成员变量的上次运行的信息. 比如:controller类里面有: Linked ...

  3. a2 任意角度选取设置

    思岚的激光雷达A2固定角度是0-360°,但是由于结构空间限制往往无法得到360°的数据,如何设置获取任意角度呢?咨询过思岚的技术支持,得到的回答是:“我们已经不支持ROS系统..”让人有点蛋疼.., ...

  4. 如何解决aws解绑银行卡问题?

    首先先来说明一下我自己的情况? 一年的免费使用 前提:没有开启任何的实例服务 先贴一条官方的解释 关于我小白一个.学校课程要求使用aws,注册之后在网络上看到一堆人踩坑,aws的扣费就是个坑! 预授权 ...

  5. 23 Maven工程module的移除和重新导入

    1.移除module 移除后: 点击右侧的maven projects: 2.重新导入刚才移除的module (1)方法1 (2)方法2 Ctrl+Shift+ALT+S的快捷键 选择modules ...

  6. Redis(八) LRU Cache

    Redis(八)-- LRU Cache 在计算机中缓存可谓无所不在,无论还是应用还是操作系统中,为了性能都需要做缓存.然缓存必然与缓存算法息息相关,LRU就是其中之一.笔者在最先接触LRU是大学学习 ...

  7. KVM虚拟机网络配置 Bridge方式,NAT方式

    https://blog.csdn.net/hzhsan/article/details/44098537/

  8. 记录RFID操作错误

    如果代码操作不了RFID设备,查看下通信协议的设置

  9. 我是如何一步步编码完成万仓网ERP系统的(十二)库存 1.概述

    https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...

  10. 华为 鸿蒙系统(HarmonyOS)

    HarmonyOS Ⅰ. 鸿蒙系统简介 鸿蒙系统(HarmonyOS),是第一款基于微内核的全场景分布式OS,是华为自主研发的操作系统.2019年8月9日,鸿蒙系统在华为开发者大会<HDC.20 ...