当前位置: 首页 > news >正文

Lambda表达式Stream流-函数式编程-java8函数式编程(Lambda表达式,Optional,Stream流)从入门到精通-最通俗易懂

一:函数式编程思想

1:概念

        面向对象思想需要关注用什么对象完成什么事情。而函数式编程思想就类似于我们数学中的函数。它主要关注的是对数据进行了什么操作

        方法的参数就是数据,方法的内容就是所做的操作。

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

2:优点

1:代码简洁

2:易于理解

3:易于并发编程:大数据量中的并行流,是通过多线程进行操作。效率更高。

二:Lambda表达式

1:概述

         Lambda来自JDK8,可以对匿名内部类进行简化。体现了函数式编程的思想。不需要关注对象,而是要关注要对什么数据做什么操作

        Lambda表达式是基于"可省略可推导"原则的,关注数据如何进行操作的函数式编程思想的,在函数式接口的匿名内部类的省略。

2:核心原则

        可推导可省略。

        方法名可推导,那么就省略方法名。

3:基本格式

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

1:匿名内部类

        Thread构造器需要传入Runnable类型的参数,那么就用匿名内部类即可,重写run方法。

        new Thread(new Runnable() {@Overridepublic void run() {System.out.println("----这是匿名内部类----");}}).start();

2:Lambda表达式进行改造

        使用Lambda表达式对匿名内部类进行简化

        简化原则:匿名内部类是一个接口,并且只有一个抽象方法。

        new Thread(new Runnable() {@Overridepublic void run() {System.out.println("----这是匿名内部类----");}}).start();

        下面是Thread中的构造方法是基于构造方法的形参,推导出来Lambda表达式的返回值的。 

new Thread(()-> System.out.println("----这是Lambda表达式----")).start();

4:Lambda表达式练习

1:练习一

    public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("新线程中的方法被执行了");}}).start();// 这里的Lambda表达式使用了函数式编程思想,// 只关注了数据和执行过程,利用类型推导,代表了匿名内部类。new Thread(() -> System.out.println("新线程中的方法被执行了")).start();}

 2:练习二

    public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("新线程中的方法被执行了");}}).start();// 这里的Lambda表达式使用了函数式编程思想,// 只关注了数据和执行过程,利用类型推导,代表了匿名内部类。new Thread(() -> System.out.println("新线程中的方法被执行了")).start();}

3:练习三

 @Testpublic void test02() {// 使用匿名内部类int i = calculateNum(new IntBinaryOperator() {@Overridepublic int applyAsInt(int left, int right) {return left+right;}});System.out.println(i);// 使用Lambda表达式,但是提供参数类型// 这里也体现了,可推导可省略的规则。int j = calculateNum((int a, int b) -> a + b);System.out.println(j);// 使用Lambda表达式int s = calculateNum((a, b) -> a + b);System.out.println(s);// replace lambda with method referenceint t = calculateNum(Integer::sum);System.out.println(t);}public static int calculateNum(IntBinaryOperator operator){int a = 10;int b = 20;return operator.applyAsInt(a, b);}

        额外调用的Java中的接口

        题外话:FunctionInterface定义在接口上,且接口中有且只有一个抽象方法。当是一个接口,并且只有一个抽象方法的时候,就可以优化成为Lambda表达式了。

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

4:练习四

    @Testpublic void test03() {// 匿名内部类printNum(new IntPredicate() {@Overridepublic boolean test(int value) {return value%2 == 0;}});// 使用Lambda表达式,但是提供参数类型// 这里也体现了,可推导可省略的规则。// return 的话,一行也需要提供{}printNum((int value) -> {return value%2 == 0;});// 使用Lambda表达式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);}}}

5:练习五

    public void test04() {// 匿名内部类Integer result = typeConver(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.valueOf(s);}});System.out.println(result);// 使用Lambda表达式Integer result1 = typeConver((String s) -> {return Integer.valueOf(s);});System.out.println(result1);// 使用Lambda表达式Integer result2 = typeConver((s) -> {return Integer.valueOf(s);});System.out.println(result2);// 匿名内部类// 定义成泛型接口,加上Lambda表达式的方式,实现方式异常的灵活。String result3 = typeConver(new Function<String, String>() {@Overridepublic String apply(String s) {return s+"三更";}});System.out.println(result3);// 最佳方式final String s1 = typeConver(s -> s + "三更");System.out.println(s1);}public static <R> R typeConver(Function<String,R> function){String str = "12345";R result =  function.apply(str);return result;}

 5:省略规则

1:参数类型可以推导,所以参数类型可以省略

2:方法只有一个参数时,小括号可以省略

3:方法体只有一句代码时,大括号、return、唯一一句代码的分号也是可以省略的。

三:Stream流概述

1:概述

        Java8的stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们对集合或数组操作。

2:数据准备

        <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.34</version></dependency>
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期去重使用
public class Author {private Long id;private String name;private Integer age;private String intro;private List<Book> books;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期去重使用
public class Book {private Long id;private String name;private String categroy;private Integer score;private String intro;
}
private static List<Author> getAuthors(){Author author = new Author(1L,"蒙多",33,"一个从猜到中明悟哲理的祖安人",null);Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);Author author3 = new Author(3L,"易",15,"是这个世界在限制他的思维",null);Author author4 = new Author(4L,"易",15,"是这个世界在限制他的思维",null);List<Book> books1 = new ArrayList<>();List<Book> books2 = new ArrayList<>();List<Book> books3 = new ArrayList<>();books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱情"));books1.add(new Book(2L,"一个人不能死在同一把刀下","个人爱情,成长",99,"讲述从失败中明悟真理"));books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解"));books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容"));books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎样的火花呢?"));author.setBooks(books1);author2.setBooks(books2);author3.setBooks(books3);author4.setBooks(books3);List<Author> authors = new ArrayList<>(Arrays.asList(author, author2, author3, author4));return authors;}

3:快速入门

1:需求

        获取作家集合,打印18岁以下的作者名字,并进行去重。

   @Testpublic void test01(){final List<Author> authors = getAuthors();authors.stream()//集合转换成流.distinct()//去重.filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() < 18;}})//过滤.forEach(new Consumer<Author>() {@Overridepublic void accept(Author author) {System.out.println(author.getAge());}});//打印authors.stream()//集合转换成流.distinct()//去重.filter(author -> author.getAge() < 18)//过滤.forEach(author-> System.out.println(author.getName()));//打印}

4:常用操作

1:创建流 

        创建流-流的中间操作-流的终结操作,必须得有终结操作,流才会被调用。否则不会被调用。

        流的代码想要被调用起来,必须得有终结方法作为结尾。否则不会被调用。

    /*** 方法目的:搞清楚流是怎么进行创建的*/@Testpublic void test02(){// 单列集合List<Author> authors = getAuthors();authors.stream();// 数组Integer[] arr = {1,2,3,4,5,6};Arrays.stream(arr);Stream.of(arr);// 双列集合 先转换为单列集合。Map<String,Integer> map = new HashMap<>();final Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();}

2:中间操作值fillter

        他的作用是过滤。

        打印姓名长度大于一的作家的姓名

    @Testpublic void test02() {final List<Author> authors = getAuthors();// 使用匿名内部类实现authors.stream().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getName().length() > 1;}}).forEach(new Consumer<Author>() {@Overridepublic void accept(Author author) {System.out.println(author.getName());}});// 使用lambda表达式实现。authors.stream().filter(author -> author.getName().length() > 1).forEach(author -> System.out.println(author.getName()));}

        匿名内部类是传入了一个匿名内部类对象,Lambda表达式是传入了一段代码(这段代码本质上值对那哪个数据对象要做哪些事。更可以理解为匿名内部类经由一系列思想简化后的产物。)

3:中间操作之map

         将流中的元素进行计算和类型转换。比方说将Stream<Author>转换为Stream<String>

        感想:Stream你就想像成流水线上的一道道工序,终结操作就是流水线的开关,只不过放在了末尾。

    @Testpublic void test03() {final List<Author> authors = getAuthors();// 使用匿名内部类实现authors.stream().map(new Function<Author, String>() {@Overridepublic String apply(Author author) {return author.getName();}}).forEach(new Consumer<String>() {@Overridepublic void accept(String name) {System.out.println(name);}});// 使用lambda表达式实现。authors.stream().map(author -> author.getName()).forEach(name -> System.out.println(name));}

4:中间操作之distinct

        可以去除流中的重复元素

        依赖object中的equals方法来判断是否相同对象,所以,需要重写方法。 

5:中间操作之sorted

         对流的元素按照年龄进行降序排序,并且要求不能有重复的因素。

        使用空参的sorted

    @Testpublic void test04(){List<Author> authors = getAuthors();authors.stream().distinct().sorted()//空参拍需,会将author转换为Compare在进行使用,如果转不了就会报错。所以,Author必须实现compare接口。.forEach(author -> System.out.println(author.getAge()));}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期去重使用
public class Author implements Comparable<Author>{private Long id;private String name;private Integer age;private String intro;private List<Book> books;@Overridepublic int compareTo(Author o) {return this.getAge()-o.getAge();}
}

        使用有参数的sorted

    @Testpublic void test05(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o1.getAge() - o2.getAge();}}).forEach(author -> System.out.println(author.getAge()));authors.stream().distinct().sorted((o1, o2) -> o1.getAge() - o2.getAge()).forEach(author -> System.out.println(author.getAge()));}

6:中间操作之limit

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

        对流中的元素按照年龄进行降序排序,不能有重复元素,打印其中年龄最大的两个作家的名字。

    @Testpublic void test06(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o1.getAge() - o2.getAge();}}).limit(2).forEach(author -> System.out.println(author.getAge()));authors.stream().distinct().sorted((o1, o2) -> o1.getAge() - o2.getAge()).limit(2).forEach(author -> System.out.println(author.getAge()));}

7:中间操作之skip

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

        打印除了年龄最大的外的其他作家,要求不能按照重复元素,并且按照年龄排序。

    @Testpublic void test06(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o1.getAge() - o2.getAge();}}).skip(1).forEach(author -> System.out.println(author.getAge()));authors.stream().distinct().sorted((o1, o2) -> o1.getAge() - o2.getAge()).skip(1).forEach(author -> System.out.println(author.getAge()));}

8:中间操作之flatMap

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

        示例一:打印所有书籍的名字,要求对重复的元素进行去重。 

    @Testpublic void test07(){List<Author> authors = getAuthors();// 这样写是有问题的写法Stream<List<Book>>,我们是没办法获取单个的对象的。authors.stream().map(new Function<Author, List<Book>>() {@Overridepublic List<Book> apply(Author author) {return author.getBooks();}}).forEach(new Consumer<List<Book>>() {@Overridepublic void accept(List<Book> books) {System.out.println(books);}});authors.stream().flatMap(new Function<Author, Stream<Book>>() {@Overridepublic Stream<Book> apply(Author author) {return author.getBooks().stream();//List<Book>转换为一个一个Stream<Book>并且拼接到一起变成一个完整的String<Book>}}).distinct().forEach(new Consumer<Book>() {@Overridepublic void accept(Book book) {System.out.println(book.getName());}});}
    @Testpublic void test08(){List<Author> authors = getAuthors();// 打印所有书籍的分类。要求对分类进行去重。不能出现这种格式:哲学,爱情authors.stream().flatMap(new Function<Author, Stream<Book>>() {@Overridepublic Stream<Book> apply(Author author) {return author.getBooks().stream();}}).distinct().flatMap(new Function<Book, Stream<String>>() {@Overridepublic Stream<String> apply(Book book) {return Arrays.stream(book.getCategroy().split(","));}}).forEach(System.out::println);authors.stream().flatMap(author->author.getBooks().stream()).distinct().flatMap(book -> Arrays.stream(book.getCategroy().split(","))).forEach(System.out::println);}

9:终结操作foreach

      相对简单不写例子了。

10:终结操作之count

     打印作家所写的书籍,注意去重

    @Testpublic void test09(){List<Author> authors = getAuthors();// 打印所有作者的书籍数量,注意去重。final long count = authors.stream().distinct().flatMap(author -> author.getBooks().stream()).distinct().count();System.out.println(count);}

     

http://www.dtcms.com/a/303300.html

相关文章:

  • React与Rudex的合奏
  • 代码解读:微调Qwen2.5-Omni 实战
  • 从单枪匹马到联盟共生:白钰玮的 IP 破局之路|创客匠人
  • 2025创始人IP如何破局?
  • 很妙的一道题 Leetcode234. 回文链表
  • windows部署ACE-Step记录
  • 从一起知名线上故障,谈配置灰度发布的重要性
  • 大模型的开发应用(十九):多模态模型基础
  • 源代码管理工具有哪些?有哪些管理场景?
  • React面试题
  • 2025年SDK游戏盾终极解析:重新定义手游安全的“隐形护甲”
  • 【Linux操作系统】简学深悟启示录:Linux环境基础开发工具使用
  • 浅谈面试中的递归算法
  • 进程通信————system V 消息队列 信号量
  • 卡内基梅隆大学提出Human2LocoMan:基于人类预训练的四足机器人「多功能操作学习框架」
  • sqlite3学习---基础知识、增删改查和排序和限制、打开执行关闭函数
  • AAAI 2025多模态重大突破:SENA框架重塑多模态学习,零标注实现自进化
  • 【Python】—— 语法糖
  • 求两数之和
  • R语言与作物模型(以DSSAT模型为例)融合应用高级实战技术
  • window显示驱动开发—Direct3D 11 视频设备驱动程序接口 (DDI)
  • 图片上传 el+node后端+数据库
  • 数据库事务中的陷阱:脏读、幻读与不可重复读
  • 第四章:分析 Redis 性能高原因和核心字符串类型命令
  • 特性阻抗的近似计算
  • 【Linux】协议——TCP/IP协议
  • PTX指令集基础以及warp级矩阵乘累加指令介绍
  • 5G MBS(组播广播服务)深度解析:从标准架构到商用实践
  • 机器学习(重学版)基础篇(算法与模型一)
  • Ansible提权sudo后执行报错