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

零、 概述
第一部分:1~3章 主要讲了行为参数化和Lambda表达式
第二部分:4~7章 主要讲了流的应用,包括流与集合差异,流的操作,收集器,注的并行执行
第三部分:8~12章 主要讲了怎样用Java8引入的特性改善老代码,Optional类和CompleteFuture及新的日期和时间API
第四部分:13~16章 主要讲了函数式编程
本文主要是对第一部分的笔记。
一、行为参数化
1.1 行为参数化定义
行为参数化就是拿出一个代码块,把它准备好却不去执行它。

1.2 举例:需求
有个果农,有如下需求:
- 从仓库中找到红色苹果
- 找出所有重量超过150g的
扩展一下:
- 可能以后还需要查找绿色苹果的功能
- 可能还需要找重量超过200g的
1.3 举例:方案1
传统实现方案
// 筛选绿色苹果
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
// 可筛选任意颜色苹果,把颜色作为参数
public static List<Apple> filterGreenApplesByColor(List<Apple> inventory, String color) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getColor().equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
// 筛选不同重量的苹果
public static List<Apple> filterGreenApplesByWeight(List<Apple> inventory, int weight) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > weight) {
result.add(apple);
}
}
return result;
}
// 写一个方法同时支持筛选颜色和重量
public static List<Apple> filterGreenApples(List<Apple> inventory, String color, int weight
, boolean filterColorFlag) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if ((filterColorFlag && apple.getColor().equals(color))
|| (!filterColorFlag && apple.getWeight() > weight)) {
result.add(apple);
}
}
return result;
}
1.4 举例:方案2
使用对象传递行为参数
interface ApplePredicate {
// 一个返回boolea值的函数,把它称为谓词
boolean test(Apple apple);
}
// 筛选绿色
public class AppleGreenColorPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return "green".equals(apple.getColor());
}
}
// 重量大于150
class AppleHeavyWeightPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getWeight() > 150;
}
}
// 红色且重量大于150
class AppleRedAndHeavyPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return "red".equals(apple.getColor()) && apple.getWeight() > 150;
}
}
// 实现
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
public void test() {
List<Apple> inventory = new ArrayList<>();
// 筛选绿色
filterApples(inventory, new AppleGreenColorPredicate());
// 重量大于150
filterApples(inventory, new AppleHeavyWeightPredicate());
// 红色且重量大于150
filterApples(inventory, new AppleRedAndHeavyPredicate());
}
1.5 举例:方案3
使用匿名类传递行为参数
// 对选择标准建模
interface ApplePredicate {
// 一个返回boolea值的函数,把它称为谓词
boolean test(Apple apple);
}
// 实现
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
public static void main(String[] args) {
List<Apple> inventory = new ArrayList<>();
// 筛选绿色
filterApples(inventory, new ApplePredicate() {
@Override
public boolean test (Apple apple){
return "green".equals(apple.getColor());
}
});
// 重量大于150
filterApples(inventory, new ApplePredicate() {
@Override
public boolean test (Apple apple){
return apple.getWeight() > 150;
}
});
// 红色且重量大于150
filterApples(inventory, new ApplePredicate() {
@Override
public boolean test (Apple apple){
return "red".equals(apple.getColor()) && apple.getWeight() > 150;
}
});
}
1.6 举例:方案4
使用Lambda表达式传递行为参数
interface ApplePredicate {
boolean test(Apple apple);
}
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if (p.test(apple)) {
result.add(apple);
}
}
return result;
}
public static void main(String[] args) {
List<Apple> inventory = new ArrayList<>();
// 筛选绿色
filterApples(inventory
, (Apple apple) -> "green".equals(apple.getColor()));
// 重量大于150
filterApples(inventory
, (Apple apple) -> apple.getWeight() > 150);
// 红色且重量大于150
filterApples(inventory
, (Apple apple) -> "red".equals(apple.getColor()) && apple.getWeight() > 150);
}
在这里小结一下:

1.7 举例:方案5
在方案4的基础上 将List类型抽象化
// 定义一个函数式接口
interface Predicate<T> {
boolean test(T t);
}
// 定义一个调用函数式接口的方法
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T e : list) {
if (p.test(e)) {
result.add(e);
}
}
return result;
}
// 使用
public static void main(String[] args) {
List<Apple> inventory = FakeDb.getApples();
List<Apple> redList = Filtering.filter(inventory
, (Apple apple) -> "red".equals(apple.getColor()));
List<String> nonEmptyList = filter(Arrays.asList("1", "", "2")
, (String s) -> !s.isEmpty());
}
二、Lambda表达式
2.1 Lambda表达式定义
简洁地表示可传递的匿名函数的一种方法。
- 匿名 {:&.fadeIn}
- 函数
- 传递
- 简洁
2.2 Lambda表达式长什么样子?

下面是5个有效的Lambda表达式
// 1 参数是String s,返回值是int
(String s) -> s.length()
// 2 参数是Apple a,返回值是boolean
(Apple a) -> a.getWeight() > 150
// 3 参数是int x,int y 没有返回值 {}内放语句,怎样区分语句与表达式
(int x, int y) -> {
System.out.println("Result:");
System.out.println(x + y);
}
// 4 无参数,返回int
() -> 42
// 5 参数是两个Apple类型的变量,返回值是boolean
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
2.3 函数式接口
函数式接口就是只定义一个抽象方法的接口。
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名,这种抽象方法叫做函数描述符
一个注解:@FunctionalInterface ,不是必须的,用于表示该接口会设计成一个函数式接口
2.4 Lambda的使用
Predicate 过滤掉列表中的空串
// 定义一个函数式接口
interface Predicate<T> {
boolean test(T t);
}
// 定义一个调用函数式接口的方法
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for (T e : list) {
if (p.test(e)) {
result.add(e);
}
}
return result;
}
// 使用
public static void main(String[] args) {
List<String> nonEmptyList = filter(Arrays.asList("1", "", "2")
, (String s) -> !s.isEmpty());
}

Consumer 计算列表中的每个元素的平方并输出
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
public static <T> void forEach(List<T> list, Consumer<T> c) {
for (T i : list) {
c.accept(i);
}
}
public static void main(String[] args) {
forEach(Arrays.asList(1, 2, 3, 4), (Integer i) -> System.out.println(i * i));
}

Function** 返回列表中每个元素的长度
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for (T s : list) {
result.add(f.apply(s));
}
return result;
}
public static void main(String[] args) {
List<Integer> result = map(Arrays.asList("1", "22", "333")
, (String s) -> s.length());
}

2.5 类型推断
List<Apple> l = new ArrayList<Apple>();
List<Apple> l = new ArrayList<>();
// Java编译器根据Lambda出现的上下文来推断Lambda表达式参数的类型
Predicate<Apple> p = (Apple a) -> 'red'.equals(a.getColor())
Predicate<Apple> p = a -> 'red'.equals(a.getColor())
2.6 方法引用
主要为了简化代码

方法引用,3种
- 指向静态方法的方法引用 String.parseInt()
- 指向实例方法的方法引用 str.length()
- 指向外部对象实例方法的方法引用 globalVar.instanceMethod()
List<String> strList = Arrays.asList("a", "b", "A", "B");
strList.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
strList.sort(String::compareToIgnoreCase); // 等效的方法引用
构造函数引用
Supplier<Apple> c1 = Apple::new; // 指向Apply()构造函数
Apple a1 = c1.get();
Function<Integer, Apple> c2 = Apple::new; // 指向Apply(int weight)构造函数
Apple a2 = c2.apply(110);
BigFunction<String, Integer, Apple> c3 = Apple::new;
// 指向Apply(String color, Integer weight)
Apple c3 = c3.apply("green", 110);
2.7 Lambda实战
根据Apple的重量来排序
// 行为参数化,下面是通过不同方式传递这个行为的
// 1.使用对象
public class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator());
// 2.使用匿名类
inventory.sort(new Comparator<Apple>(){
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
});
// 3.使用Lambda表达式
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
// 因为类型推断,可以简化成
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
// 因为有个java.util.Comparator.comparing静态方法,还可以简化成
import static java.util.Comparator.comparing;
inventory.sort(comparing((a) -> a.getWeight()));
// 4.使用方法引用
inventory.sort(comparing(comparing(Apple::getWeight)));
2.8 复合Lambda表达式
比较器复合
// 逆序,苹果按重量递减排序
inventory.sort(comparing(Apple::getWeight).reversed());
// 比较器链,先按重量递减排序再按国家排序
inverntory.sort(comparing(Apple::getWeight).reversed()
.thenComparing(Apple::getCountry));
谓词复合
// negate,and,or
// 筛选不是红苹果
Predicate<Apple> notRedApple = redApple.negate();
// 筛选红苹果且重量大于150 或 绿苹果
redApple.and(a -> a.getWeight() > 150).or(a -> "green".equals(a.getColor()));
// a.or(b).and(c) <==> (a || b) && c
函数复合
// andThen,compose
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
// g(f(x))
Function<Integer, Integer> h = f.andThen(g);
int result = h.apply(1);
// f(g(x))
Function<Integer, Integer> h = f.compose(g);
int result = h.apply(1);
三、代码
https://gitee.com/yysue/tutorials-java/tree/master/java-8
行为参数化与lambda表达式 - 读《Java 8实战》的更多相关文章
- Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】
原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...
- Lambda 表达式 in java 8
Lambda 表达式 in Java 8 Lambda表达式是java 8 新增的特性 Lambda表达式主要作用:支持将代码块作为方法参数,允许使用更简洁的代码创建函数式接口的实例,是匿名内部类的一 ...
- Lambda 表达式,Java中应用Lambda 表达式
一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...
- 行为参数化和Lambda表达式
行为参数化是指拿出一个代码块把他准备好却不执行它.这个代码块以后可以被程序的其他部分调用,意味着你可以推迟这块代码的执行.方法接受多种行为作为参数,并在内部使用来完成不同的行为.行为参数话的好处在于可 ...
- Lambda表达式和Java集合框架
本文github地址 前言 我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起. 为引入Lambda表达式,Java8新增了java.util. ...
- Java 8 (2) 使用Lambda表达式
什么是Lambda? 可以把Lambda表达式理解为 简洁的表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表.函数主体.返回类型,可能还有一个可以抛出的异常列表. 使用Lambda可以让你更 ...
- Java 8新特性(一):Lambda表达式
2014年3月发布的Java 8,有可能是Java版本更新中变化最大的一次.新的Java 8为开发者带来了许多重量级的新特性,包括Lambda表达式,流式数据处理,新的Optional类,新的日期和时 ...
- Java 8特性探究(1):通往lambda之路与 lambda表达式10个示例
本文由 ImportNew 函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是只包含一个方法的接口.比如Java标准库中的ja ...
- 深入浅出 Java 8 Lambda 表达式
摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...
随机推荐
- MATLAB与Carsim联合仿真时提示matlab not found的解决方法(CarSim在联合仿真时提示找不到MATLAB的解决方法)
CarSim8.02并没有提供选择联合仿真的MATLAB/Simulink的版本的功能,CarSim总是与最后安装的MATLAB/Simulink进行联合仿真,如果安装有多个matlab版本则只打开最 ...
- 【Android开发】Android 颜色透明度换算
透明度 透明度分为256阶(0-255),计算机上用16进制表示为(00-ff). 透明就是0阶,不透明就是255阶,如果50%透明就是127阶(256的一半当然是128,但因为是从0开始,所以实际上 ...
- pdm的说明
软件行业的JAVA代码静态分析工具 PMD是一种开源分析Java代码错误的工具.与其他分析工具不同的是,PMD通过静态分析获知代码错误.也就是说,在不运行Java程序的情况下报告错误.PMD附带了许多 ...
- java_类的访问控制符
1.分类: public protected default private是java中的访问控制修饰符. public String name; protected String name; Str ...
- Java学习day32
生产与消费者问题:假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者从仓库中取走产品:如果仓库中没有产品,生产者就将产品放入仓库,否则就停止生产等待:如果仓库中有产品,消费者就取走,否 ...
- CF #781 (Div. 2), (C) Tree Infection
Problem - C - Codeforces Example input 5 7 1 1 1 2 2 4 5 5 5 1 4 2 1 3 3 1 6 1 1 1 1 1 output 4 4 2 ...
- Blazor Bootstrap 组件库浏览器通知组件介绍
通知组件 通过浏览器API发送通知信息 , 桌面浏览器表现为右下角系统提示框弹出消息, 移动浏览器表现为弹窗或者到消息列表, blazor页面不在前台也可以通过本组件提醒用户. DEMO https: ...
- css 进阶实战项目
1. html 结构 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- python基础练习题(题目 文本颜色设置)
day23 --------------------------------------------------------------- 实例035:设置输出颜色 题目 文本颜色设置. 分析:不会, ...
- Spring 源码(4)在Spring配置文件中自定义标签如何实现?
Spring 配置文件自定义标签的前置条件 在上一篇文章https://www.cnblogs.com/redwinter/p/16165274.html Spring BeanFactory的创建过 ...