函数式编程

  • 函数式接口:参数是一个接口,并且接口中只有一个方法。
  • 不关心接口、方法的名字,只关心方法的参数和方法体
  • 选中函数式接口,直接生成Lambda表达式快捷键 alt+enter

一、Lambda表达式

(参数列表) ->{代码}
省略规则:

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略
  • 以上这些规则都记不住也可以省略不记 alt+enter: Lambda转换成原来的代码

没有参数

 public static void main(String[] args) {
        //以前的代码
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("大家好");
            }
        }).start();
		
		// Lambda表达式
        new Thread(() ->{
            System.out.println("早上好");
        }).start();
    }

有参数

 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);

		// Lambda表达式
		int i = calculateNum((int left, int right)-> {
                return left * right;
            });
        System.out.println(i);
        
 		// Lambda表达式简写
        int i1 = calculateNum((left, right) -> left * right);
        System.out.println(i1);

 		// 参数是一个函数式接口
    public static int calculateNum(IntBinaryOperator operator) {
        int a = 10;
        int b = 20;
        return operator.applyAsInt(a, b);
    }

1.1 alt+enter:Lambda转换成原来的代码

在这里插入图片描述

二、Stream流

  • 对集合和数组进行链状流式的操作,更加方便操作集合和数组。
  • 以前的是IO流,读写数据用的。这里的Stream流是对集合数组进行操作。

2.1 Debug过程

在这里插入图片描述

准备代码:实体类代码

//作者
public class Author implements Comparable<Author>{
    private Long id;
    private String name;
    private String introduction;
    private Integer age;
    private List<Book> bookList;
}

//书
public class Book {
    private Long id;
    private String category;
    private String name;
    private Double score;
    private String introduction;
}

//产品
public class Product{
    int id;
    String name;
    Double price;
}

  // 初始化一些数据
    private static List<Author> getAuthors() {
        Author author1 = new Author(1L, "杨杰炜", "my introduction 1", 18, null);
        Author author2 = new Author(2L, "yjw", "my introduction 2", 19, null);
        Author author3 = new Author(3L, "yjw", "my introduction 3", 14, null);
        Author author4 = new Author(4L, "wdt", "my introduction 4", 29, null);
        Author author5 = new Author(5L, "wtf", "my introduction 5", 12, null);

        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        // 上面是作者和书
        books1.add(new Book(1L, "类别,分类啊", "书名1", 45D, "这是简介哦"));
        books1.add(new Book(2L, "高效", "书名2", 84D, "这是简介哦"));
        books1.add(new Book(3L, "喜剧", "书名3", 83D, "这是简介哦"));

        books2.add(new Book(5L, "天啊", "书名4", 65D, "这是简介哦"));
        books2.add(new Book(6L, "高效", "书名5", 89D, "这是简介哦"));

        books3.add(new Book(7L, "久啊", "书名6", 45D, "这是简介哦"));
        books3.add(new Book(8L, "高效", "书名7", 44D, "这是简介哦"));
        books3.add(new Book(9L, "喜剧", "书名8", 81D, "这是简介哦"));

        author1.setBookList(books1);
        author2.setBookList(books2);
        author3.setBookList(books3);
        author4.setBookList(books3);
        author5.setBookList(books2);

        return new ArrayList<>(Arrays.asList(author1, author2, author3, author4, author5));
    }

2.2 入门案例

调用getAuthors方法获取到作家的集合。打印所有年龄小于18的作家的名字,并且要注意去重。

private static void test1(){
        List<Author> authors = getAuthors();
        authors.stream()   //把集合转换成流
                .distinct() //去重
                .filter(author -> author.getAge()<18)  //筛选年龄小于18
                .forEach(author -> System.out.println(author.getName())); //遍历打印名字
        
    }

2.3 方法

2.3.1 创建流

单列集合

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();

数组

 Integer[] arr = {1,2,3,4};
 //方式一
 Stream<Integer> stream = Arrays.stream(arr);
 //方式二
  Stream<Integer> stream = Stream.of(arr);

双列集合:转换成单列集合再创建

Map<String,Integer> map = new HashMap<>();
map.put("波吉", 15);
map.put("卡克", 14);
map.put("波斯", 13);
Stream<Map.Entry<String,Integer>> stream = map.entrySet().stream();

2.3.2 中间操作

filter

可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中

//打印所有姓名长度大于1的作家的姓名
   private static void test() {
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length()>1)
                .forEach(author -> System.out.println(author.getName()));

    }
 
map

对流中的元素进行计算或转换


//打印所有作家的姓名
  private static void test(List<Author> authors) {

        authors.stream() // 返回值是stream对象,也就是集合转流          
                .map(author -> author.getName()) // 只要名字
                .distinct() // 去重,这里不能放在前面,不然比较的是author元素不是名字
                .forEach(System.out::println); // 遍历输出
    }
authors.stream()Stream  
		.map(author -> author.getAge())
		.map(age -> age+10)
		.forEach(age -> System.out.println(age));
distinct

可以去除流中的重复元素
注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。

sorted

可以对流中的元素进行排序
注意:如果调用空参的sorted()方法,需要流中的元紊是实现了Comparable。

在这里插入图片描述

@Data
@EqualsAndHashCode
public class Author implements Comparable<Author>{
    private Long id;
    private String name;
    private String introduction;
    private Integer age;
    private List<Book> bookList;
    
   /** 使用sorted时比较整个元素时,要实现比较接口,并重写方法
     */
    @Override
    public int compareTo(Author o) {
        // 0表示年纪一样大,负数表示传入的大
        // 这里sorted如果输出的是降序,你就把这俩顺序对换就可以了,不用记忆
        return o.getAge() - this.getAge();
    }
}
limit

可以设置流的最大长度,超出的部分将被抛弃。

在这里插入图片描述

skip

跳过流中的前个元素,返回剩下的元素

在这里插入图片描述

flatMap

map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。

在这里插入图片描述
在这里插入图片描述

2.3.3 终结操作

forEach

对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体操作。

在这里插入图片描述

count

可以用来获取当前流中元素的个数。

在这里插入图片描述

max & min

可以用来获取流中的最值。

在这里插入图片描述

collect

把当前流转换成一个集合。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查找与匹配 — anyMatch

可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型。

在这里插入图片描述

查找与匹配 — allMatch

可以用来判断是否都符合匹配条件,结果为boolean类型。如果都符合结果为true,否则结果为false。

在这里插入图片描述

查找与匹配 — noneMatch

可以判断流中的元索是否都不符合匹配条件。如果都不符合结果为true,否则结果为fase

在这里插入图片描述

查找与匹配 — findany

获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。

在这里插入图片描述

查找与匹配 — findFirst

获取流中的第一个元素。

在这里插入图片描述

reduce归并

对流中的数据按照你指定的计算方式计算出一个结果。
(缩减操作)
reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和在初始化值的基础上进行计算计算结果再和后面的元素计算

reduce两个参数的重载形式内部的计算原理:
在这里插入图片描述

案例1:
在这里插入图片描述
案例2:
在这里插入图片描述
案例3:

在这里插入图片描述

reduce一个参数的重载形式内部的计算原理:

    private static void test19() {
        Optional<Integer> reduce = getAuthors().stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce((result, element) -> result < element ? result : element);
        System.out.println("单个参数的reduce方法使用,作者中年龄最小的是:" + reduce.get());
    }

三、Optional

  • 我们在编写代码的时候会出现空指针异常,所以很多情况下需要做各种非空判断。尤其是对象中属性还是一个对象的情况下。但过多的判断会让我们的代码显得臃肿。
  • Optional就可以帮助我们写出更优雅的代码来避免空指针异常

使用

3.1 创建对象

  • Optional就好像是包装类,可以把我们的具体数据封装Optionaly对象内部。然后我们去使用Optionale中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。
3.1.1 Optional的静态方法ofNullable
  • 一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题。

在这里插入图片描述

3.1.2 Optional的静态方法empty

在这里插入图片描述

3.2 安全消费值ifPresent

我们获取到一个Optional对象后肯定需要对其中的数据进行使用。可以使用其ifPresent方法对来消费其中的值。
这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。

例如,以下写法就优雅的避免了空指针异常。

Optional<Author> authoroptional = optional.ofNullable(getAuthor ());
authoroptional.ifPresent(author -> System.out.println(author.getName()));

3.3 获取值 get()

不推荐

3.4 安全获取值

推荐

3.4.1 orElseGet

获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返
回。

在这里插入图片描述

3.4.2 orElseThrow

获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出。

3.5 过滤

我们可以使用flter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optionaly对象。

在这里插入图片描述

3.6 判断

我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处,更推荐使用ifPresent方法。

在这里插入图片描述

3.7 数据转换

Optionali还提供了map可以让我们的对数据进行转换,并且转换得到的数据也还是被Optionalf包装好的,保证了我们的使用安全。

在这里插入图片描述

四、函数式接口

  • 只有一个抽象方法的接口我们称之为函数接口。
  • JDK的函数式接口都加上了@Functionallnterface注解进行标识。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。

五、方法引用

  • 我们在使用lambdal时,如果方法体中只有一个方法的调用的话(包括构造方法),我们可以用方法引用进一步简化代码。
  • 类名或者对象名::方法名
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值