主要内容
自定义函数式接口
函数式编程
常用函数式接口
Stream 流
方法引用
学习目标
能够使用 @FunctionalInterface 注解
能够自定义无参无返回函数式接口
能够自定义有参有返回函数式接口
能够理解 Lambda 延迟执行的特点
能够使用 Lambda 作为方法的参数
能够使用 Lambda 作为方法的返回值
能够使用 Supplier 函数式接口
能够使用 Consumer 函数式接口
能够使用 Function<T, R > 函数式接口
能够使用 Predicate 函数式接口
能够理解流与集合相比的优点
能够理解流的延迟执行特点
能够通过集合, 映射或数组获取流
能够掌握常用的流操作
能够使用输出语句的方法引用
能够通过 4 种方式使用方法引用
能够使用类和数组的构造器引用
第一章 函数式接口
1.1 概念
函数式接口在 Java 中是指: 有且仅有一个抽象方法的接口.
函数式接口, 即适用于函数式编程场景的接口. 而 Java 中的函数式编程体现就是 Lambda, 所以函数式接口就是可以适用于 Lambda 使用的接口. 只有确保接口中有且仅有一个抽象方法, Java 中的 Lambda 才能顺利地进行推导.
备注:"语法糖" 是指使用更加方便, 但是原理不变的代码语法. 例如在遍历集合时使用的 for-each 语法, 其实底层的实现原理仍然是迭代器, 这便是 "语法糖". 从应用层面来讲, Java 中的 Lambda 可以被当做是匿名内部类的 "语法糖", 但是二者在原理上是不同的.
1.2 格式
只要确保接口中有且仅有一个抽象方法即可:
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
- // 其他非抽象方法内容
- }
由于接口当中抽象方法的 public abstract 是可以省略的, 所以定义一个函数式接口很简单:
- public interface MyFunctionalInterface {
- void myMethod();
- }
1.3 @FunctionalInterface 注解
与 @Override 注解的作用类似, Java 8 中专门为函数式接口引入了一个新的注解:@FunctionalInterface. 该注解可用于一个接口的定义上:
- @FunctionalInterface
- public interface MyFunctionalInterface {
- void myMethod();
- }
一旦使用该注解来定义接口, 编译器将会强制检查该接口是否确实有且仅有一个抽象方法, 否则将会报错. 需要注意的是, 即使不使用该注解, 只要满足函数式接口的定义, 这仍然是一个函数式接口, 使用起来都一样.
1.4 自定义函数式接口
对于刚刚定义好的 MyFunctionalInterface 函数式接口, 典型使用场景就是作为方法的参数:
- public class Demo09FunctionalInterface {
- // 使用自定义的函数式接口作为方法参数
- private static void doSomething(MyFunctionalInterface inter) {
- inter.myMethod(); // 调用自定义的函数式接口方法
- }
- public static void main(String[] args) {
- // 调用使用函数式接口的方法
- doSomething(() -> System.out.println("Lambda 执行啦!"));
- }
- }
第二章 函数式编程
在兼顾面向对象特性的基础上, Java 语言通过 Lambda 表达式与方法引用等, 为开发者打开了函数式编程的大门. 下面我们做一个初探.
2.1 Lambda 的延迟执行
有些场景的代码执行后, 结果不一定会被使用, 从而造成性能浪费. 而 Lambda 表达式是延迟执行的, 这正好可以作为解决方案, 提升性能.
性能浪费的日志案例
注: 日志可以帮助我们快速的定位问题, 记录程序运行过程中的情况, 以便项目的监控和优化.
一种典型的场景就是对参数进行有条件使用, 例如对日志消息进行拼接后, 在满足条件的情况下进行打印输出:
- public class Demo01Logger {
- private static void log(int level, String msg) {
- if (level == 1) {
- System.out.println(msg);
- }
- }
- public static void main(String[] args) {
- String msgA = "Hello";
- String msgB = "World";
- String msgC = "Java";
- log(1, msgA + msgB + msgC);
- }
- }
这段代码存在问题: 无论级别是否满足要求, 作为 log 方法的第二个参数, 三个字符串一定会首先被拼接并传入方法内, 然后才会进行级别判断. 如果级别不符合要求, 那么字符串的拼接操作就白做了, 存在性能浪费.
备注: SLF4J 是应用非常广泛的日志框架, 它在记录日志时为了解决这种性能浪费的问题, 并不推荐首先进行字符串的拼接, 而是将字符串的若干部分作为可变参数传入方法中, 仅在日志级别满足要求的情况下才会进行字符串拼接. 例如: LOGGER.debug("变量 {} 的取值为 {}.", "os", "macOS"), 其中的大括号{} 为占位符. 如果满足日志级别要求, 则会将 "os" 和 "macOS" 两个字符串依次拼接到大括号的位置; 否则不会进行字符串拼接. 这也是一种可行解决方案, 但 Lambda 可以做到更好.
体验 Lambda 的更优写法
使用 Lambda 必然需要一个函数式接口:
- @FunctionalInterface
- public interface MessageBuilder {
- String buildMessage();
- }
然后对 log 方法进行改造:
- public class Demo02LoggerLambda {
- private static void log(int level, MessageBuilder builder) {
- if (level == 1) {
- System.out.println(builder.buildMessage());
- }
- }
- public static void main(String[] args) {
- String msgA = "Hello";
- String msgB = "World";
- String msgC = "Java";
- log(1, () -> msgA + msgB + msgC );
- }
- }
这样一来, 只有当级别满足要求的时候, 才会进行三个字符串的拼接; 否则三个字符串将不会进行拼接.
证明 Lambda 的延迟
下面的代码可以通过结果进行验证:
- public class Demo03LoggerDelay {
- private static void log(int level, MessageBuilder builder) {
- if (level == 1) {
- System.out.println(builder.buildMessage());
- }
- }
- public static void main(String[] args) {
- String msgA = "Hello";
- String msgB = "World";
- String msgC = "Java";
- log(2, () -> {
- System.out.println("Lambda 执行!");
- return msgA + msgB + msgC;
- });
- }
- }
从结果中可以看出, 在不符合级别要求的情况下, Lambda 将不会执行. 从而达到节省性能的效果.
扩展: 实际上使用内部类也可以达到同样的效果, 只是将代码操作延迟到了另外一个对象当中通过调用方法来完成. 而是否调用其所在方法是在条件判断之后才执行的.
2.2 使用 Lambda 作为参数和返回值
如果抛开实现原理不说, Java 中的 Lambda 表达式可以被当作是匿名内部类的替代品. 如果方法的参数是一个函数式接口类型, 那么就可以使用 Lambda 表达式进行替代. 使用 Lambda 表达式作为方法参数, 其实就是使用函数式接口作为方法参数.
例如 java.lang.Runnable 接口就是一个函数式接口, 假设有一个 startThread 方法使用该接口作为参数, 那么就可以使用 Lambda 进行传参. 这种情况其实和 Thread 类的构造方法参数为 Runnable 没有本质区别.
- public class Demo04Runnable {
- private static void startThread(Runnable task) {
- new Thread(task).start();
- }
- public static void main(String[] args) {
- startThread(() -> System.out.println("线程任务执行!"));
- }
- }
类似地, 如果一个方法的返回值类型是一个函数式接口, 那么就可以直接返回一个 Lambda 表达式. 当需要通过一个方法来获取一个 java.util.Comparator 接口类型的对象作为排序器时, 就可以调该方法获取.
- import java.util.Arrays;
- import java.util.Comparator;
- public class Demo06Comparator {
- private static Comparator<String> newComparator() {
- return (a, b) -> b.length() - a.length();
- }
- public static void main(String[] args) {
- String[] array = { "abc", "ab", "abcd" };
- System.out.println(Arrays.toString(array));
- Arrays.sort(array, newComparator());
- System.out.println(Arrays.toString(array));
- }
- }
其中直接 return 一个 Lambda 表达式即可.
第三章 常用函数式接口
JDK 提供了大量常用的函数式接口以丰富 Lambda 的典型使用场景, 它们主要在 java.util.function 包中被提供. 下面是最简单的几个接口及使用示例.
3.1 Supplier 接口
java.util.function.Supplier<T > 接口仅包含一个无参的方法: T get(). 用来获取一个泛型参数指定类型的对象数据. 由于这是一个函数式接口, 这也就意味着对应的 Lambda 表达式需要 "对外提供" 一个符合泛型类型的对象数据.
- import java.util.function.Supplier;
- public class Demo08Supplier {
- private static String getString(Supplier<String> function) {
- return function.get();
- }
- public static void main(String[] args) {
- String msgA = "Hello";
- String msgB = "World";
- System.out.println(getString(() -> msgA + msgB));
- }
- }
练习: 求数组元素最大值
题目
使用 Supplier 接口作为方法参数类型, 通过 Lambda 表达式求出 int 数组中的最大值. 提示: 接口的泛型请使用 java.lang.Integer 类.
解答
- public class Demo02Test {
- // 定一个方法, 方法的参数传递 Supplier, 泛型使用 Integer
- public static int getMax(Supplier<Integer> sup){
- return sup.get();
- }
- public static void main(String[] args) {
- int arr[] = {2,3,4,52,333,23};
- // 调用 getMax 方法, 参数传递 Lambda
- int maxNum = getMax(()->{
- // 计算数组的最大值
- int max = arr[0];
- for(int i : arr){
- if(i>max){
- max = i;
- }
- }
- return max;
- });
- System.out.println(maxNum);
- }
- }
3.3 Consumer 接口
java.util.function.Consumer<T > 接口则正好与 Supplier 接口相反, 它不是生产一个数据, 而是消费一个数据, 其数据类型由泛型决定.
抽象方法: accept
Consumer 接口中包含抽象方法 void accept(T t), 意为消费一个指定泛型的数据. 基本使用如:
- import java.util.function.Consumer;
- public class Demo09Consumer {
- private static void consumeString(Consumer<String> function) {
- function.accept("Hello");
- }
- public static void main(String[] args) {
- consumeString(s -> System.out.println(s));
- }
- }
当然, 更好的写法是使用方法引用.
默认方法: andThen
如果一个方法的参数和返回值全都是 Consumer 类型, 那么就可以实现效果: 消费数据的时候, 首先做一个操作, 然后再做一个操作, 实现组合. 而这个方法就是 Consumer 接口中的 default 方法 andThen. 下面是 JDK 的源代码:
- default Consumer<T> andThen(Consumer<? super T> after) {
- Objects.requireNonNull(after);
- return (T t) -> { accept(t); after.accept(t); };
- }
备注: java.util.Objects 的 requireNonNull 静态方法将会在参数为 null 时主动抛出 NullPointerException 异常. 这省去了重复编写 if 语句和抛出空指针异常的麻烦.
要想实现组合, 需要两个或多个 Lambda 表达式即可, 而 andThen 的语义正是 "一步接一步" 操作. 例如两个步骤组合的情况:
- import java.util.function.Consumer;
- public class Demo10ConsumerAndThen {
- private static void consumeString(Consumer<String> one, Consumer<String> two) {
- one.andThen(two).accept("Hello");
- }
- public static void main(String[] args) {
- consumeString(
- s -> System.out.println(s.toUpperCase()),
- s -> System.out.println(s.toLowerCase()));
- }
- }
运行结果将会首先打印完全大写的 HELLO, 然后打印完全小写的 hello. 当然, 通过链式写法可以实现更多步骤的组合.
3.4 练习: 格式化打印信息
题目
下面的字符串数组当中存有多条信息, 请按照格式 "姓名: XX. 性别: XX." 的格式将信息打印出来. 要求将打印姓名的动作作为第一个 Consumer 接口的 Lambda 实例, 将打印性别的动作作为第二个 Consumer 接口的 Lambda 实例, 将两个 Consumer 接口按照顺序 "拼接" 到一起.
- public static void main(String[] args) {
- String[] array = { "迪丽热巴, 女", "古力娜扎, 女", "马尔扎哈, 男" };
- }
解答
- import java.util.function.Consumer;
- public class DemoConsumer {
- public static void main(String[] args) {
- String[] array = { "迪丽热巴, 女", "古力娜扎, 女", "马尔扎哈, 男" };
- printInfo(s -> System.out.print("姓名:" + s.split(",")[0]),
- s -> System.out.println(". 性别:" + s.split(",")[1] + "."),
- array);
- }
- private static void printInfo(Consumer<String> one, Consumer<String> two, String[] array) {
- for (String info : array) {
- one.andThen(two).accept(info); // 姓名: 迪丽热巴. 性别: 女.
- }
- }
- }
3.5 Predicate 接口
有时候我们需要对某种类型的数据进行判断, 从而得到一个 boolean 值结果. 这时可以使用 java.util.function.Predicate<T > 接口.
抽象方法: test
Predicate 接口中包含一个抽象方法: boolean test(T t). 用于条件判断的场景:
- import java.util.function.Predicate;
- public class Demo15PredicateTest {
- private static void method(Predicate<String> predicate) {
- boolean veryLong = predicate.test("HelloWorld");
- System.out.println("字符串很长吗:" + veryLong);
- }
- public static void main(String[] args) {
- method(s -> s.length()> 5);
- }
- }
条件判断的标准是传入的 Lambda 表达式逻辑, 此处为只要字符串长度大于 5 则认为很长.
默认方法: and
既然是条件判断, 就会存在与, 或, 非三种常见的逻辑关系. 其中将两个 Predicate 条件使用 "与" 逻辑连接起来实现 "并且" 的效果时, 可以使用 default 方法 and. 其 JDK 源码为:
- default Predicate<T> and(Predicate<? super T> other) {
- Objects.requireNonNull(other);
- return (t) -> test(t) && other.test(t);
- }
如果要判断一个字符串既要包含大写 "H", 又要包含大写 "W", 那么:
- import java.util.function.Predicate;
- public class Demo16PredicateAnd {
- private static void method(Predicate<String> one, Predicate<String> two) {
- boolean isValid = one.and(two).test("Helloworld");
- System.out.println("字符串符合要求吗:" + isValid);
- }
- public static void main(String[] args) {
- method(s -> s.contains("H"), s -> s.contains("W"));
- }
- }
默认方法: or
与 and 的 "与" 类似, 默认方法 or 实现逻辑关系中的 "或".JDK 源码为:
- default Predicate<T> or(Predicate<? super T> other) {
- Objects.requireNonNull(other);
- return (t) -> test(t) || other.test(t);
- }
如果希望实现逻辑 "字符串包含大写 H 或者包含大写 W", 那么代码只需要将 "and" 修改为 "or" 名称即可, 其他都不变:
- import java.util.function.Predicate;
- public class Demo16PredicateAnd {
- private static void method(Predicate<String> one, Predicate<String> two) {
- boolean isValid = one.or(two).test("Helloworld");
- System.out.println("字符串符合要求吗:" + isValid);
- }
- public static void main(String[] args) {
- method(s -> s.contains("H"), s -> s.contains("W"));
- }
- }
默认方法: negate
"与","或" 已经了解了, 剩下的 "非"(取反)也会简单. 默认方法 negate 的 JDK 源代码为:
- default Predicate<T> negate() {
- return (t) -> !test(t);
- }
从实现中很容易看出, 它是执行了 test 方法之后, 对结果 boolean 值进行 "!" 取反而已. 一定要在 test 方法调用之前调用 negate 方法, 正如 and 和 or 方法一样:
- import java.util.function.Predicate;
- public class Demo17PredicateNegate {
- private static void method(Predicate<String> predicate) {
- boolean veryLong = predicate.negate().test("HelloWorld");
- System.out.println("字符串很长吗:" + veryLong);
- }
- public static void main(String[] args) {
- method(s -> s.length() <5);
- }
- }
3.6 练习: 集合信息筛选
题目
数组当中有多条 "姓名 + 性别" 的信息如下, 请通过 Predicate 接口的拼装将符合要求的字符串筛选到集合 ArrayList 中, 需要同时满足两个条件:
必须为女生.
姓名为 4 个字.
- public class DemoPredicate {
- public static void main(String[] args) {
- String[] array = {
- "迪丽热巴, 女", "古力娜扎, 女", "马尔扎哈, 男", "赵丽颖, 女"
- };
- }
- }
解答
- import java.util.ArrayList;
- import java.util.List;
- import java.util.function.Predicate;
- public class DemoPredicate {
- public static void main(String[] args) {
- String[] array = { "迪丽热巴, 女", "古力娜扎, 女", "马尔扎哈, 男", "赵丽颖, 女" };
- List<String> list = filter(array,
- s -> "女".equals(s.split(",")[1]),
- s -> s.split(",")[0].length() == 4);
- System.out.println(list);
- }
- private static List<String> filter(String[] array, Predicate<String> one,
- Predicate<String> two) {
- List<String> list = new ArrayList<>();
- for (String info : array) {
- if (one.and(two).test(info)) {
- list.add(info);
- }
- }
- return list;
- }
- }
3.7 Function 接口
java.util.function.Function<T,R > 接口用来根据一个类型的数据得到另一个类型的数据, 前者称为前置条件, 后者称为后置条件.
抽象方法: apply
Function 接口中最主要的抽象方法为: R apply(T t), 根据类型 T 的参数获取类型 R 的结果.
使用的场景例如: 将 String 类型转换为 Integer 类型.
- import java.util.function.Function;
- public class Demo11FunctionApply {
- private static void method(Function<String, Integer> function) {
- int num = function.apply("10");
- System.out.println(num + 20);
- }
- public static void main(String[] args) {
- method(s -> Integer.parseInt(s));
- }
- }
当然, 最好是通过方法引用的写法.
默认方法: andThen
Function 接口中有一个默认的 andThen 方法, 用来进行组合操作. JDK 源代码如:
- default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
- Objects.requireNonNull(after);
- return (T t) -> after.apply(apply(t));
- }
该方法同样用于 "先做什么, 再做什么" 的场景, 和 Consumer 中的 andThen 差不多:
- import java.util.function.Function;
- public class Demo12FunctionAndThen {
- private static void method(Function<String, Integer> one, Function<Integer, Integer> two) {
- int num = one.andThen(two).apply("10");
- System.out.println(num + 20);
- }
- public static void main(String[] args) {
- method(str->Integer.parseInt(str)+10, i -> i *= 10);
- }
- }
第一个操作是将字符串解析成为 int 数字, 第二个操作是乘以 10. 两个操作通过 andThen 按照前后顺序组合到了一起.
请注意, Function 的前置条件泛型和后置条件泛型可以相同.
3.8 练习: 自定义函数模型拼接
题目
请使用 Function 进行函数模型的拼接, 按照顺序需要执行的多个函数操作为:
String str = "赵丽颖, 20";
将字符串截取数字年龄部分, 得到字符串;
将上一步的字符串转换成为 int 类型的数字;
将上一步的 int 数字累加 100, 得到结果 int 数字.
解答
- import java.util.function.Function;
- public class DemoFunction {
- public static void main(String[] args) {
- String str = "赵丽颖, 20";
- int age = getAgeNum(str, s -> s.split(",")[1],
- s ->Integer.parseInt(s),
- n -> n += 100);
- System.out.println(age);
- }
- private static int getAgeNum(String str, Function<String, String> one,
- Function<String, Integer> two,
- Function<Integer, Integer> three) {
- return one.andThen(two).andThen(three).apply(str);
- }
- }
第四章 Stream 流
说到 Stream 便容易想到 I/O Stream, 而实际上, 谁规定 "流" 就一定是 "IO 流" 呢? 在 Java 8 中, 得益于 Lambda 所带来的函数式编程, 引入了一个全新的 Stream 概念, 用于解决已有集合类库既有的弊端.
- import java.util.ArrayList;
- import java.util.List;
- public class Demo01ForEach {
- public static void main(String[] args) {
- List<String> list = new ArrayList<>();
- list.add("张无忌");
- list.add("周芷若");
- list.add("赵敏");
- list.add("张强");
- list.add("张三丰");
- for (String name : list) {
- System.out.println(name);
- }
- }
- }
- import java.util.ArrayList;
- import java.util.List;
- public class Demo02NormalFilter {
- public static void main(String[] args) {
- List<String> list = new ArrayList<>();
- list.add("张无忌");
- list.add("周芷若");
- list.add("赵敏");
- list.add("张强");
- list.add("张三丰");
- List<String> zhangList = new ArrayList<>();
- for (String name : list) {
- if (name.startsWith("张")) {
- zhangList.add(name);
- }
- }
- List<String> shortList = new ArrayList<>();
- for (String name : zhangList) {
- if (name.length() == 3) {
- shortList.add(name);
- }
- }
- for (String name : shortList) {
- System.out.println(name);
- }
- }
- }
- import java.util.ArrayList;
- import java.util.List;
- public class Demo03StreamFilter {
- public static void main(String[] args) {
- List<String> list = new ArrayList<>();
- list.add("张无忌");
- list.add("周芷若");
- list.add("赵敏");
- list.add("张强");
- list.add("张三丰");
- list.stream()
- .filter(s -> s.startsWith("张"))
- .filter(s -> s.length() == 3)
- .forEach(System.out::println);
- }
- }
- import java.util.*;
- import java.util.stream.Stream;
- public class Demo04GetStream {
- public static void main(String[] args) {
- List<String> list = new ArrayList<>();
- // ...
- Stream<String> stream1 = list.stream();
- Set<String> set = new HashSet<>();
- // ...
- Stream<String> stream2 = set.stream();
- Vector<String> vector = new Vector<>();
- // ...
- Stream<String> stream3 = vector.stream();
- }
- }
- import java.util.HashMap;
- import java.util.Map;
- import java.util.stream.Stream;
- public class Demo05GetStream {
- public static void main(String[] args) {
- Map<String, String> map = new HashMap<>();
- // ...
- Stream<String> keyStream = map.keySet().stream();
- Stream<String> valueStream = map.values().stream();
- Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
- }
- }
- import java.util.stream.Stream;
- public class Demo06GetStream {
- public static void main(String[] args) {
- String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
- Stream<String> stream = Stream.of(array);
- }
- }
- import java.util.stream.Stream;
- public class Demo12StreamForEach {
- public static void main(String[] args) {
- Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
- stream.forEach(name-> System.out.println(name));
- }
- }
- import java.util.stream.Stream;
- public class Demo07StreamFilter {
- public static void main(String[] args) {
- Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
- Stream<String> result = original.filter(s -> s.startsWith("张"));
- }
- }
- import java.util.stream.Stream;
- public class Demo08StreamMap {
- public static void main(String[] args) {
- Stream<String> original = Stream.of("10", "12", "18");
- Stream<Integer> result = original.map(str->Integer.parseInt(str));
- }
- }
- import java.util.stream.Stream;
- public class Demo09StreamCount {
- public static void main(String[] args) {
- Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
- Stream<String> result = original.filter(s -> s.startsWith("张"));
- System.out.println(result.count()); // 2
- }
- }
- import java.util.stream.Stream;
- public class Demo10StreamLimit {
- public static void main(String[] args) {
- Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
- Stream<String> result = original.limit(2);
- System.out.println(result.count()); // 2
- }
- }
- import java.util.stream.Stream;
- public class Demo11StreamSkip {
- public static void main(String[] args) {
- Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");
- Stream<String> result = original.skip(2);
- System.out.println(result.count()); // 1
- }
- }
- import java.util.stream.Stream;
- public class Demo12StreamConcat {
- public static void main(String[] args) {
- Stream<String> streamA = Stream.of("张无忌");
- Stream<String> streamB = Stream.of("张翠山");
- Stream<String> result = Stream.concat(streamA, streamB);
- }
- }
- import java.util.ArrayList;
- import java.util.List;
- public class DemoArrayListNames {
- public static void main(String[] args) {
- // 第一支队伍
- ArrayList<String> one = new ArrayList<>();
- one.add("迪丽热巴");
- one.add("宋远桥");
- one.add("苏星河");
- one.add("石破天");
- one.add("石中玉");
- one.add("老子");
- one.add("庄子");
- one.add("洪七公");
- // 第二支队伍
- ArrayList<String> two = new ArrayList<>();
- two.add("古力娜扎");
- two.add("张无忌");
- two.add("赵丽颖");
- two.add("张三丰");
- two.add("尼古拉斯赵四");
- two.add("张天爱");
- two.add("张二狗");
- // ....
- }
- }
- public class Person {
- private String name;
- public Person() {}
- public Person(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return "Person{name='" + name + "'}";
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- public class DemoArrayListNames {
- public static void main(String[] args) {
- List<String> one = new ArrayList<>();
- // ...
- List<String> two = new ArrayList<>();
- // ...
- // 第一个队伍只要名字为 3 个字的成员姓名;
- List<String> oneA = new ArrayList<>();
- for (String name : one) {
- if (name.length() == 3) {
- oneA.add(name);
- }
- }
- // 第一个队伍筛选之后只要前 3 个人;
- List<String> oneB = new ArrayList<>();
- for (int i = 0; i <3; i++) {
- oneB.add(oneA.get(i));
- }
- // 第二个队伍只要姓张的成员姓名;
- List<String> twoA = new ArrayList<>();
- for (String name : two) {
- if (name.startsWith("张")) {
- twoA.add(name);
- }
- }
- // 第二个队伍筛选之后不要前 2 个人;
- List<String> twoB = new ArrayList<>();
- for (int i = 2; i <twoA.size(); i++) {
- twoB.add(twoA.get(i));
- }
- // 将两个队伍合并为一个队伍;
- List<String> totalNames = new ArrayList<>();
- totalNames.addAll(oneB);
- totalNames.addAll(twoB);
- // 根据姓名创建 Person 对象;
- List<Person> totalPersonList = new ArrayList<>();
- for (String name : totalNames) {
- totalPersonList.add(new Person(name));
- }
- // 打印整个队伍的 Person 对象信息.
- for (Person person : totalPersonList) {
- System.out.println(person);
- }
- }
- }
- Person{
- name='宋远桥'
- }
- Person{
- name='苏星河'
- }
- Person{
- name='石破天'
- }
- Person{
- name='张天爱'
- }
- Person{
- name='张二狗'
- }
- import java.util.ArrayList;
- import java.util.List;
- import java.util.stream.Stream;
- public class DemoStreamNames {
- public static void main(String[] args) {
- List<String> one = new ArrayList<>();
- // ...
- List<String> two = new ArrayList<>();
- // ...
- // 第一个队伍只要名字为 3 个字的成员姓名;
- // 第一个队伍筛选之后只要前 3 个人;
- Stream<String> streamOne = one.stream().filter(s -> s.length() == 3).limit(3);
- // 第二个队伍只要姓张的成员姓名;
- // 第二个队伍筛选之后不要前 2 个人;
- Stream<String> streamTwo = two.stream().filter(s -> s.startsWith("张")).skip(2);
- // 将两个队伍合并为一个队伍;
- // 根据姓名创建 Person 对象;
- // 打印整个队伍的 Person 对象信息.
- Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println);
- }
- }
- Person{
- name='宋远桥'
- }
- Person{
- name='苏星河'
- }
- Person{
- name='石破天'
- }
- Person{
- name='张天爱'
- }
- Person{
- name='张二狗'
- }
- @FunctionalInterface
- public interface Printable {
- void print(String str);
- }
- public class Demo01PrintSimple {
- private static void printString(Printable data) {
- data.print("Hello, World!");
- }
- public static void main(String[] args) {
- printString(s -> System.out.println(s));
- }
- }
- public class Demo02PrintRef {
- private static void printString(Printable data) {
- data.print("Hello, World!");
- }
- public static void main(String[] args) {
- printString(System.out::println);
- }
- }
- @FunctionalInterface
- public interface PrintableInteger {
- void print(int str);
- }
- public class Demo03PrintOverload {
- private static void printInteger(PrintableInteger data) {
- data.print(1024);
- }
- public static void main(String[] args) {
- printInteger(System.out::println);
- }
- }
- public class MethodRefObject {
- public void printUpperCase(String str) {
- System.out.println(str.toUpperCase());
- }
- }
- @FunctionalInterface
- public interface Printable {
- void print(String str);
- }
- public class Demo04MethodRef {
- private static void printString(Printable lambda) {
- lambda.print("Hello");
- }
- public static void main(String[] args) {
- MethodRefObject obj = new MethodRefObject();
- printString(obj::printUpperCase);
- }
- }
- @FunctionalInterface
- public interface Calcable {
- int calc(int num);
- }
- public class Demo05Lambda {
- private static void method(int num, Calcable lambda) {
- System.out.println(lambda.calc(num));
- }
- public static void main(String[] args) {
- method(-10, n -> Math.abs(n));
- }
- }
- public class Demo06MethodRef {
- private static void method(int num, Calcable lambda) {
- System.out.println(lambda.calc(num));
- }
- public static void main(String[] args) {
- method(-10, Math::abs);
- }
- }
- @FunctionalInterface
- public interface Greetable {
- void greet();
- }
- public class Human {
- public void sayHello() {
- System.out.println("Hello!");
- }
- }
- public class Man extends Human {
- @Override
- public void sayHello() {
- System.out.println("大家好, 我是 Man!");
- }
- // 定义方法 method, 参数传递 Greetable 接口
- public void method(Greetable g){
- g.greet();
- }
- public void show(){
- // 调用 method 方法, 使用 Lambda 表达式
- method(()->{
- // 创建 Human 对象, 调用 sayHello 方法
- new Human().sayHello();
- });
- // 简化 Lambda
- method(()->new Human().sayHello());
- // 使用 super 关键字代替父类对象
- method(()->super.sayHello());
- }
- }
- public class Man extends Human {
- @Override
- public void sayHello() {
- System.out.println("大家好, 我是 Man!");
- }
- // 定义方法 method, 参数传递 Greetable 接口
- public void method(Greetable g){
- g.greet();
- }
- public void show(){
- method(super::sayHello);
- }
- }
- @FunctionalInterface
- public interface Richable {
- void buy();
- }
- public class Husband {
- private void marry(Richable lambda) {
- lambda.buy();
- }
- public void beHappy() {
- marry(() -> System.out.println("买套房子"));
- }
- }
- public class Husband {
- private void buyHouse() {
- System.out.println("买套房子");
- }
- private void marry(Richable lambda) {
- lambda.buy();
- }
- public void beHappy() {
- marry(() -> this.buyHouse());
- }
- }
- public class Husband {
- private void buyHouse() {
- System.out.println("买套房子");
- }
- private void marry(Richable lambda) {
- lambda.buy();
- }
- public void beHappy() {
- marry(this::buyHouse);
- }
- }
- public class Person {
- private String name;
- public Person(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- public interface PersonBuilder {
- Person buildPerson(String name);
- }
- public class Demo09Lambda {
- public static void printName(String name, PersonBuilder builder) {
- System.out.println(builder.buildPerson(name).getName());
- }
- public static void main(String[] args) {
- printName("赵丽颖", name -> new Person(name));
- }
- }
- public class Demo10ConstructorRef {
- public static void printName(String name, PersonBuilder builder) {
- System.out.println(builder.buildPerson(name).getName());
- }
- public static void main(String[] args) {
- printName("赵丽颖", Person::new);
- }
- }
- @FunctionalInterface
- public interface ArrayBuilder {
- int[] buildArray(int length);
- }
- public class Demo11ArrayInitRef {
- private static int[] initArray(int length, ArrayBuilder builder) {
- return builder.buildArray(length);
- }
- public static void main(String[] args) {
- int[] array = initArray(10, length -> new int[length]);
- }
- }
- public class Demo12ArrayInitRef {
- private static int[] initArray(int length, ArrayBuilder builder) {
- return builder.buildArray(length);
- }
- public static void main(String[] args) {
- int[] array = initArray(10, int[]::new);
- }
- }
来源: https://www.cnblogs.com/p1ng/p/12286944.html