hincky的主页 hincky的主页
  • 学习笔记

    • Vue笔记
    • Vuepress
    • nginx
  • 语言类

    • java
    • go
    • python
    • 设计模式
  • 框架类

    • Spring
    • Spring Security
    • Mybatis
  • 容器技术

    • docker
    • k8s
    • helm
    • prometheus
    • grafana
    • jenkins
  • 命令集合

    • linux命令
    • docker命令
    • git命令
    • vim命令
    • k8s命令
  • 数据库

    • sql
    • mysql
  • 协议

    • 网络模型
    • http/1.1
    • WebSocket
    • http/2
    • TLS/SSL
    • tcp
    • IP
    • tcpdump抓包命令
    • wireshark抓包工具
  • 通用

    • Git
  • 技术分享

    • git push/pull总是超时怎么办
    • idea debug技巧
    • postman使用
    • 问题总结
    • idea使用技巧
  • Oauth2

    • Oauth2原理
  • 项目列表

    • redis项目
    • 微服务项目
  • 分类
  • 标签
  • 归档
  • 随笔
GitHub (opens new window)

Hincky

当有趣的人,做想做的事
  • 学习笔记

    • Vue笔记
    • Vuepress
    • nginx
  • 语言类

    • java
    • go
    • python
    • 设计模式
  • 框架类

    • Spring
    • Spring Security
    • Mybatis
  • 容器技术

    • docker
    • k8s
    • helm
    • prometheus
    • grafana
    • jenkins
  • 命令集合

    • linux命令
    • docker命令
    • git命令
    • vim命令
    • k8s命令
  • 数据库

    • sql
    • mysql
  • 协议

    • 网络模型
    • http/1.1
    • WebSocket
    • http/2
    • TLS/SSL
    • tcp
    • IP
    • tcpdump抓包命令
    • wireshark抓包工具
  • 通用

    • Git
  • 技术分享

    • git push/pull总是超时怎么办
    • idea debug技巧
    • postman使用
    • 问题总结
    • idea使用技巧
  • Oauth2

    • Oauth2原理
  • 项目列表

    • redis项目
    • 微服务项目
  • 分类
  • 标签
  • 归档
  • 随笔
GitHub (opens new window)
  • java

    • java并发
      • cpu
      • Thread几个常用方法
      • Thread类和Runnable接口的比较
    • 函数式编程-lambda
      • Lambda表达式
        • 例一
        • 例二
        • 例三
        • 例四
        • 例五
      • 省略规则
      • 高级格式
        • 引用类的静态方法
        • 引用对象的实例方法
        • 引用类的实例方法
        • 构造器引用
    • 函数式编程-stream
      • 案例数据准备
      • 快速入门
        • 需求
        • 实现
      • 常用操作
        • 创建流
        • 中间操作
        • filter
        • map
        • distinct
        • sorted
        • limit
        • skip
        • flatMap
        • 终结操作
        • forEach
        • count
        • max&min
        • collect
        • 查找与匹配
        • anyMatch
        • allMatch
        • noneMatch
        • findAny
        • findFirst
        • reduce归并
      • 注意事项
    • 函数式编程-optional
      • 使用
        • 创建对象
        • 安全消费值
        • 获取值
        • 安全获取值
        • 过滤
        • 判断
        • 数据转换
    • 函数式接口
      • 常见函数式接口
      • 常用的默认方法
        • and
        • or
        • negate
    • 函数式编程高级用法
      • 基本数据类型优化
      • 并行流
    • IO流-文件
      • 介绍
      • 文件
      • 文件操作
        • 创建文件
        • 获取文件信息
  • python

  • Spring

  • SpringMVC

  • SpringSecurity

  • Mybatis

  • 设计模式

  • Go

  • 后端
  • java
hincky
2022-11-10
目录

函数式编程-lambda

为什么学

  • 看懂其他人的代码
  • 大数量下处理集合效率高
  • 代码可读性高
  • 消灭嵌套地狱

以下是没有用函数式编程的方法

List<Book> bookList = new ArrayList<>();
Set<Book> uniqueBookValues = new HashSet<>();
Set<Author> uniqueAuthorValues = new HashSet<>();
for (Author author : authors){
    if(uniqueAuthorValues.add(author)){
        if(author.getAge() < 18){
            List<Book> books = author.getBooks();
            for(Book book : books){
                if(book.getScore() > 70){
                    if(uniqueBookValues.add(book)){
                        bookList.add(book);
                    }
                }
            }
        }
    }
}
System.out.println(bookList);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

警告

嵌套严重,层级十分的多

下面使用函数式编程

List<Book> collect = author.stream()
    .distinct()
    .filter(author -> author.getAge() < 18)
    .map(author -> author.getBooks())
    .flatMap(Collection::stream)
    .filter(book -> book.getScore() > 70)
    .distinct()
    .collect(Collection.toList());
System.out.println(collect);
1
2
3
4
5
6
7
8
9

优点:

  • 代码简洁,开发快速
  • 接近自然语言,易于理解
  • 易于多人协作编程

# Lambda表达式

核心原则:可推导可省略

Lambda是JDK8中一个语法糖。他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。

基本格式:

(参数列表)->{代码}
1

什么情况下可以用lambda进行简化: 如果方法参数中是一个接口类型的匿名内部类,且类中只有一个抽象方法需要重写;这时就可以用lambda进行简化;

重点关注抽象方法中的参数和方法体

# 例一

我们在创建线程并启动时可以使用匿名内部类的写法:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("test");
    }
}).start();
1
2
3
4
5
6

可以使用Lambda的格式对其进行修改。修改后如下:

new Thread(
    ()->{System.out.println("test");}
).start();
1
2
3

# 例二

现有方法定义如下,其中IntBinaryOperator是一个接口。先使用匿名内部类的写法调用该方法。

public static int calculateNum(IntBinaryOperator operator){
    int a = 10;
    int b = 20;
    return operator.applyAsInt(a, b);
}

public static void main(String[] args) {
    int i = calculateNum(new IntBinaryOperator() {
        @Override
        public int applyAsInt(int left, int right) {
            return left + right;
        }
    });
    System.out.println(i);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Lambda写法:

public static void main(String[] args) {
    int i = calculateNum((int left, int right)->{
        return left + right;
    });
    System.out.println(i);
}
1
2
3
4
5
6

# 例三

现有方法定义如下,其中IntPredicate是一个接口。先使用匿名内部类的写法调用该方法。

public static void printNum(IntPredicate predicate){
    int[] arr = {1,2,3,4,5,6,7,8,9,10};
    for (int i : arr) {
        if(predicate.test(i)){
            System.out.println(i);
        }
    }
}
public static void main(String[] args) {
    printNum(new IntPredicate() {
        @Override
        public boolean test(int value) {
            return value%2==0;
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Lambda写法:

public static void main(String[] args) {
    printNum((int value)-> {
        return value%2==0;
    });
}
public static void printNum(IntPredicate predicate){
    int[] arr = {1,2,3,4,5,6,7,8,9,10};
    for (int i : arr) {
        if(predicate.test(i)){
            System.out.println(i);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 例四

现有方法定义如下,其中Function是一个接口。先使用匿名内部类的写法调用该方法。

public static <R> R typeConver(Function<String,R> function){
    String str = "1235";
    R result = function.apply(str);
    return result;
}
public static void main(String[] args) {
    Integer result = typeConver(new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return Integer.valueOf(s);
        }
    });
    System.out.println(result);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Lambda写法:

public static void main(String[] args) {
    Integer result = typeConver((String s)->{
        return Integer.valueOf(s);
    });
    System.out.println(result);
}
1
2
3
4
5
6

# 例五

现有方法定义如下,其中IntConsumer是一个接口。先使用匿名内部类的写法调用该方法。

public static void foreachArr(IntConsumer consumer){
    int[] arr = {1,2,3,4,5,6,7,8,9,10};
    for (int i : arr) {
        consumer.accept(i);
    }
}
public static void main(String[] args) {
    foreachArr(new IntConsumer() {
        @Override
        public void accept(int value) {
            System.out.println(value);
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Lambda写法:

public static void main(String[] args) {
    foreachArr((int value)->{
        System.out.println(value);
    });
}
1
2
3
4
5

# 省略规则

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略
  • 以上这些规则都记不住也可以省略不记

# 高级格式

# 引用类的静态方法

使用前提

​如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。

格式:

类名::方法名
1

例如:

如下代码就可以用方法引用进行简化

List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();

authorStream.map(author -> author.getAge())
        .map(age->String.valueOf(age));
1
2
3
4
5
6

注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。

优化后如下:

List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();

authorStream.map(author -> author.getAge())
        .map(String::valueOf);
1
2
3
4
5
6

# 引用对象的实例方法

使用前提

​如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法

格式:

对象名::方法名
1

例如:

List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName())
        .forEach(name->sb.append(name));
1
2
3
4
5
6

优化后:

List<Author> authors = getAuthors();

Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName())
        .forEach(sb::append);
1
2
3
4
5
6

# 引用类的实例方法

使用前提

​如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。

格式:

类名::方法名
1

例如:

interface UseString{
    String use(String str,int start,int length);
}

public static String subAuthorName(String str, UseString useString){
    int start = 0;
    int length = 1;
    return useString.use(str,start,length);
}
public static void main(String[] args) {

    subAuthorName("三更草堂", new UseString() {
        @Override
        public String use(String str, int start, int length) {
            return str.substring(start,length);
        }
    });

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

优化后如下:

public static void main(String[] args) {

    subAuthorName("三更草堂", String::substring);

}
1
2
3
4
5

# 构造器引用

​如果方法体中的一行代码是构造器的话就可以使用构造器引用。

使用前提

​如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。

格式:

类名::new
1

例如:

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getName())
        .map(name->new StringBuilder(name))
        .map(sb->sb.append("-三更").toString())
        .forEach(str-> System.out.println(str));
1
2
3
4
5
6

优化后:

List<Author> authors = getAuthors();
authors.stream()
        .map(author -> author.getName())
        .map(StringBuilder::new)
        .map(sb->sb.append("-三更").toString())
        .forEach(str-> System.out.println(str));
1
2
3
4
5
6
编辑 (opens new window)
#java
java并发
函数式编程-stream

← java并发 函数式编程-stream→

最近更新
01
人生前期重要的能力
05-17
02
防火墙命令
04-11
03
docker-compose部署mysql主从集群
03-22
更多文章>
Theme by Vdoing | Copyright © 2022-2023 Hincky | MIT License | 粤ICP备2022120427号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式