深入显出Java函数式编程

一、基本介绍

"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。
它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。

函数式编程优点:

  • 代码简介开发迅速
  • 接近自然语言,易于理解
  • 易于并发编程

二、Lambda表达式

1、优点

不关注对象是什么,不关注方法名是什么,只关注如何操作数据
可推导可省略
对匿名内部类(是接口且仅有一个抽象方法)进行简化

2、基本格式

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

例1:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Lambda表达式学习");
    }
}).start();

/** Lambda表示:*/
new Thread(() -> {
    System.out.println("Lambda表达式学习");
}).start();

例2:

@FunctionalInterface
public interface IntBinaryOperator {

    /**
     * Applies this operator to the given operands.
     *
     * @param left the first operand
     * @param right the second operand
     * @return the operator result
     */
    int applyAsInt(int left, int right);
}


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


/** 普通写法:*/
    int i = calculateNum(new IntBinaryOperator() {
            @Override
            public int applyAsInt(int left, int right) {
                return left + right;
            }
        });
/** lambda表达式:*/
   int i = calculateNum((left, right) -> {
            return left + right;
        });

例3:

 @FunctionalInterface
public interface IntPredicate {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param value the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(int value);
    }
    
    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);
            }
        }
    }
   /**
     * predicate.test(i) 说明:
     * 该方法返回是一个布尔类型,只有test方法返回的是true才会执行
     */
/** 普通写法:*/
       printNum(new IntPredicate() {
            @Override
            public boolean test(int value) {
                return value % 2 == 0;
            }
        });
/** lambda表达式:*/
     printNum((value)->{
     		return value%2==0;
     });
         

3、进一步优化

  • 参数类型可以省略(上述例子全部省略)
  • 方体体只有一句代码时,大括号、return、分号可以省略例如:
    如例3 可写为: printNum((value) -> value % 2 == 0);
  • 方法体只有一个参数时小括号也可以省略
    再改写:printNum(value -> value % 2 == 0);

三、方法引用

lambda表达式再一次改进
基本格式:
类名或对象名::方法名

什么时候用?

我也不太懂 只会alter+enter

例: .mapToInt(author -> author.getAge())
改进:.mapToInt(Author::getAge)

四、Stream流🔺

1、简介

优点:更加简便的操作集合和对象

2、准备案例

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Author{
    private Long id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private int age;
    /**
     * 作品
     */
    private List<Book> books;

    public Integer getHHH(int age,String name){
        return Integer.valueOf(age+name);
    }
}



@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
    private Long id;
    /**
     * 题目
     */
    private String title;
    /**
     * 分类
     */
    private String category;
    /**
     * 价格
     */
    private double price;
}


    private static List<Author> getAuthors() {
        Book book = new Book(1L, "JavaSE", "JAVA", 200);
        Book book1 = new Book(2L, "Python精通", "Python", 205);
        Book book2 = new Book(3L, "JAVAEE", "JAVA", 28);
        Book book3 = new Book(4L, "C++Prime", "C++", 2254);
        Book book4 = new Book(5L, "JAVAWeb", "JAVA,Web", 445);
        Book book5 = new Book(6L, "Redis", "database,Linux", 54);
        Book book6 = new Book(7L, "Mysql", "database", 545);

        List<Book> list = new ArrayList<>();
        List<Book> list1 = new ArrayList<>();
        List<Book> list2 = new ArrayList<>();

        list.add(book);
        list.add(book1);
        list.add(book2);
        list.add(book2);

        list1.add(book3);
        list1.add(book4);

        list2.add(book6);
        list2.add(book6);
        list2.add(book5);

        Author author = new Author(1L, "Mae", 21, list);
        Author author1 = new Author(2L, "Strive", 25, list1);
        Author author2 = new Author(3L, "Naomi", 28, list2);
        Author author3 = new Author(3L, "Naomi", 28, list2);

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

3、创建流操作

  • 单列集合:集合对象.stream()

    	//例: 
    	List<Author> authorList=getAuthorList(); 
    		authorList.stream();		                        
    
  • 多列集合:map.entrySet.stream();

     	//例:
     	Map<String,String> map=new HashMap<>();
     	map.entrySet.stream();
    
  • 数组:Arrays.stream(数组名)

4、中间操作(过滤、排序、去重、转换等等)

(1)、filter

过滤操作
例:输出年龄大于25的作家

       List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getAge()>25)
                .forEach(author -> System.out.println(author));

在这里插入图片描述
过滤后只剩下两条
在这里插入图片描述

(2)、distinct

去重
案例:打印年龄超过25的作家 并且去重

      List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getAge()>25)
                .distinct()
                .forEach(author -> System.out.println(author));

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

(3)、map

对流中的元素进行计算或转换(类型)
例:将对象按照年龄转成Integer 然后将年龄加10

        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge())
                .distinct()
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));

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

(4)、sorted

排序
例:按照年龄降序

        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge())
                .distinct()
                .sorted((o1, o2) -> o2-o1)
                .forEach(age -> System.out.println(age));

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

(5)、limit

限制流的最大长度
案例:打印年龄最大的两个作家(需去重和排序)

   List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .limit(2)
                .forEach(author -> System.out.println(author));

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

(6)、skip

跳过所定义长度的流
案例:打印除了最大年龄的所有作家

     List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author));

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

(7)、flatmap

将一个对象转换成多个对象
例 打印所有书籍名字 并去除

     List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book ));

使用 flatmap 将一个作家集合转换成多个书本集合
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

例 打印所有书本分类 并去重(注意属于多个分类的书籍)

	    List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(s -> System.out.println(s));

关键:将属于多个分类的书籍 用逗号分隔转换成数组,然后再用数组的stream()方法 转化成流
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、终结操作

终结操作是stream流中必须的,如果没有终结操作,那么中间操作将不会执行

(1)、forEach

对流中的元素进行遍历
前面的案例都用forEach作为终结操作

(2)、count

获取流中元素个数
例:获取书本个数(去重)

在这里插入图片描述

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

(3)、min&max

获取流中元素的最小值和最大值
例:获取年龄最大的作者

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

(4)、collect

把当前流转换成一个集合
案例 转成成set集合 键为作者,值为书名

  List<Author> authors = getAuthors();
        Map<String, List<Book>> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(map);

在这里插入图片描述

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

(5)、anyMatch

判断是否有符合匹配条件的元素
例:判断是否有年龄大于25的作家

    List<Author> authors = getAuthors();
        boolean b = authors.stream()
                .anyMatch(author -> author.getAge() > 25);

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

(6)、allMatch

判断所有元素是否都符合条件

(7)、noneMatch

判断是否都不符合条件

(8)、findAny

找到任意一个符合条件的元素

(9)、findFirst

找到第一个符合条件的元素

(10)、reduce🔺

对流中的数据按照指定规则方式计算出一个结果
例 求作者年龄之和(去重)

      List<Author> authors = getAuthors();
        Integer sum = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (result, age) -> (result + age));
        System.out.println(sum);

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

6、基本数据类型转化优化

不使用map,而使用mapToInt/Double/Long、flatMapToInt/Double/Long

List<Author> authors = getAuthors();
    authors.stream()
            .mapToInt(author -> author.getAge())
            .forEach(value -> System.out.println(value));

7、Stream流总结

  • 流是惰性求值,即不进行终结操作,中间操作也不会执行
  • 流是一次性的,对一个集合创建了流,不能再对其进行第二次创流
  • 不影响原数据

四、Optional🔺

1、作用

主要为了避免开发过程中出现空指针异常
空指针确实很烦
Exception in thread "main" java.lang.NullPointerException

2、使用Optional避免空指针异常

使用ofNullable获取对象(无论是否为空)
使用ifPresent 如果不为空则执行 为空则不会执行

 List<Author> authors = getAuthors();
        Optional<List<Author>> authorListOptional = Optional.ofNullable(authors);
        authorListOptional.ifPresent(authors1 -> System.out.println(authors1));

3、有关Optional

Optional中还有许多方法与Stream流中类似
在这里插入图片描述
不演示了

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mae_strive

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值