• Java函数式编程Lambda和Stream流


    一、概述

    优点
    • 大数据量下处理集合效率高,自动创建并发流,提高多线程性能
    • 代码可读性高
    • 消灭嵌套
    编程思想

    ​ 面向对象思想需要关注对象做什么,函数式编程主要关注对数据的处理

    二、Lambda表达式

    2.1 概述

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

    函数式接口:指的是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,这样的接口可以隐式转换为 Lambda 表达式

    2.2 核心原则

    可推导可省略

    2.3 基本公式

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

    例一

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

    改为Lambda表达式

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

    例二

    public static <R> R typeConver(Function<String, R> function) {
    	String str = "123";
    	R result = function.apply(str);
    	return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    改为Lambda表达式第一步

    Integer result = typeConver(new Function<String, Interger>(){
    	@Override
    	public Interger apply(String s){
    		return Integer.valueOf(s);
    	}
    });
    System.out.println(result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    第二步

    Integer result = typeConver(s -> Integer.valueOf(s));
    System.out.println(result);
    
    • 1
    • 2

    2.4 省略规则

    • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值
    • 可选参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号
    • 可选大括号:如果主体包含了一个语句,就不需要使用大括号
    • 可选返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指明表达式返回了一个数值

    2.5 变量作用域

    Lambda表达式可以引用类成员和局部变量,但是会将这些变量隐式的转化成final

    String separator = ","; 
    Arrays.asList( "a", "b", "c" ).forEach( 
        ( String e ) -> System.out.print( e + separator ) ); 
    
    • 1
    • 2
    • 3
    final String separator = ","; 
    Arrays.asList( "a", "b", "c" ).forEach( 
        ( String e ) -> System.out.print( e + separator ) ); 
    
    • 1
    • 2
    • 3

    两者等价。

    同时,Lambda 表达式的局部变量可以不用声明为final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)

    int num = 1; 
    Arrays.asList(1,2,3,4).forEach(e -> System.out.println(num + e)); 
    num =2; 
    //报错信息:Local variable num defined in an enclosing scope must be final or effectively final 
    
    • 1
    • 2
    • 3
    • 4
    int num = 1; 
    Arrays.asList(1,2,3,4).forEach(num -> System.out.println(num)); 
    //报错信息:Variable 'num' is already defined in the scope 
    
    • 1
    • 2
    • 3

    三、Stream流

    3.1 概述

    Stream使用的是函数式编程模式,可以被用来对集合或数组进行链状流式的操作。

    3.2 示例

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public class Author {
        private Long id;
        private String name;
        private String intro;
        private Integer age;
        private List<Book> books;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public class Book {
        private Long id;
        private String name;
        private String category;
        private Integer score;
        private String intro;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    public static List<Author> getAuthors() {
    
        List<Book> books1 = new LinkedList<>();
        List<Book> books2 = new LinkedList<>();
        List<Book> books3 = new LinkedList<>();
    
        books1.add(new Book(11L,"book11","category11",18, "intro1"));
        books1.add(new Book(12L,"book12","category12",17, "intro12"));
    
        books2.add(new Book(21L,"book21","category21",27, "intro2"));
        books2.add(new Book(22L,"book22","category22",28, "intro21"));
        books2.add(new Book(23L,"book23","category23",29, "intro23"));
    
        books3.add(new Book(31L,"book31","category31",39, "intro31"));
        books3.add(new Book(32L,"book32","category32",32, "intro32"));
        books3.add(new Book(33L,"book33","category33",33, "intro33"));
        books3.add(new Book(34L,"book34","category34",34, "intro34"));
    
        Author author1 = new Author(1L,"author1","intro1",11, books1);
        Author author2 = new Author(2L,"author2","intro2",22, books2);
        Author author3 = new Author(3L,"author3","intro3",33, books3);
    
        List<Author> authors = new LinkedList<>();
        authors.add(author1);
        authors.add(author2);
        authors.add(author3);
    
        return authors;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
        public static void main(String[] args) {
            List<Author> authors = getAuthors();
            Stream<Author> stream = authors.stream();
            stream
                    .distinct()
                    .filter(author -> author.getAge()<=22)
                    .forEach(System.out::println);
    
            System.out.println("ccccc"+authors);
            stream.forEach(System.out::println);
        }
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    请添加图片描述

    NOTE:

    • Stream 操作不改变原有数据,author的值没有变化
    • 终结操作后,stream流不可再用,因为已经被操作或者关闭

    学习过程中一个好用的工具

    请添加图片描述

    可以查看stream每一步对数据的处理。

    3.3 常用操作

    请添加图片描述

    3.3.1 创建流

    单列集合

    对象.Stream()即可

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

    数组

    Arrays.stream(arr)或者是用Stream.of来创建

    Integer[] arr = [1,2,3,4,5];
    Stream<Interger> stream = Arrays.stream(arr);
    Stream<Interger> stream2 = Stream.of(arr);
    
    • 1
    • 2
    • 3

    双列集合\

    先转化为单列形式,再转化

    Map<String, Integer> map = new HashMap<>();
    map.put("age1",11);
    map.put("age2",22);
    map.put("age3",33);
    Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
    Stream<Map.Entry<String, Integer>> stream = entrySet.stream();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    3.3.2 中间操作
    • distinct
    • filter
    • map
    • sorted
    • limit
    • skip
    • flatMap
    3.3.3 终结操作
    • forEach
    • count
    • min&max
    • collect
    • anyMatch
    • allMatch
    • findAny
    • findFirst
    • reduce

    3.4 注意事项

    • 惰性求值,没有终结操作,中间操作是不能执行的。
    • 流是一次性的,一旦这个流对象经过终结操作后,这个流不可再被使用。
    • 不会影响原数据,上面已给示例。
  • 相关阅读:
    ElasticSearch8.4.3 Springboot 复杂查询
    05-Mycat的概念
    《高性能网站建设进阶指南》阅读笔记
    Java 转型问题(向上转型和向下转型)
    探索APP性能优化之稳定性优化(解决方案)
    Android 自定义Edittext 和TextView 提示文字和填入内容不同的粗细组件
    C语言用筛选法求 100 之内的素数(挖去 1,被除数平方根)
    [附源码]Python计算机毕业设计Django人员信息管理
    软考__第17章 战略管理
    Java入门教程(11) ——基本数据类型
  • 原文地址:https://blog.csdn.net/StillTogether/article/details/126424563