《Java-SE-第三十三章》之函数式编程

news2024/11/28 8:41:48

前言

在你立足处深挖下去,就会有泉水涌出!别管蒙昧者们叫嚷:“下边永远是地狱!”

博客主页:KC老衲爱尼姑的博客主页

博主的github,平常所写代码皆在于此

共勉:talk is cheap, show me the code

作者是爪哇岛的新手,水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


文章目录

  • 函数式编程
    • 概念
    • 函数式接口
      • 常见的函数式接口
    • Lambda表达式
      • 概述
        • 示例一
        • 示例二
        • 示例三
        • 示例四
        • 示例五
          • Lambda省略规则
    • Stream流
      • 常规操作
        • 1. 创建流
          • (1)单列集合:集合对象.stream()
          • (2)数组:Arrays.stream(数组)或者使用Stream.of()来创建
          • (3)双列集合:双列集合无法直接转成流必须转成单列集合在创建流
        • 2. 中间操作
          • filter
          • map
          • distinct
          • sorted
          • limit
          • skip
          • flatMap
          • concat
          • forEach
          • count
          • max&min
          • collect
        • 3. 查找与匹配
            • anyMatch
            • allMatch
            • noneMatch
            • findFirst
            • reduce
        • 4. 函数式接口中默认方法
          • 1. and
          • 2. or
          • 3. negate
      • 注意事项
    • 高级用法
        • 流元素类型转换
        • 并行流


函数式编程

概念

 面向对象是需要关注用什么对象去解决什么问头。而函数式编程,“它是一种使用函数进行编程的方式”,它关注是数据进行了什么操作。

函数式接口

 要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。

注意:

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口

  2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。

常见的函数式接口

  • ​ Consumer 消费接口

    根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。

在这里插入图片描述

  • ​ Function 计算转换接口

    根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回

在这里插入图片描述

  • ​ Predicate 判断接口

    根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果

    在这里插入图片描述

  • ​ Supplier 生产型接口

    根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回

在这里插入图片描述

Lambda表达式

概述

 Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression,基于数学中的λ演算得名,也可称为闭包(Closure) 。

Lambda表达式的语法

基本语法: (parameters) -> expression(parameters) ->{ statements; }

Lambda表达式由三部分组成:

  1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。

  2. ->:可理解为“被用于”的意思

  3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。

Lambda基本使用

示例一

我们使用匿名内部类的方式创建并启动线程:

public class Demo {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World");
            }
        }).start();
    }
}

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

public class Demo {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("Hello World")).start();
    }
}

可以简化的匿名内部类必须是函数式接口,函数式接口就是被@FunctionalInterface修饰的接口,同时该接口只有一个抽象方法。

示例二

使用IntBinaryOperator接口计算两个数的和,还是先试用匿名内部类的方式

import java.util.function.IntBinaryOperator;

public class Demo2 {
    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);//30
    }
}

Lambda写法:

public class Demo2 {
    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((left, right) -> left + right);
        System.out.println(i);
    }
}

示例三

使用IntPredicate接口判读数字是否是偶数,先使用匿名内部类的写法调用该方法。


import java.util.function.IntPredicate;

public class Demo3 {
    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) {
        //允许你定义并传递一个接受整数参数并返回布尔值的函数IntPredicate
        printNum(new IntPredicate() {
            @Override
            public boolean test(int value) {
                return value%2==0;
            }
        });
    }
}

Lambda写法:


import java.util.function.IntPredicate;

public class Demo3 {
    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) {
        //允许你定义并传递一个接受整数参数并返回布尔值的函数IntPredicate
        printNum(value -> value%2==0);
    }
}

示例四

使用Function接口将字符串转成成Integer类型,IntConsumer,先使用匿名内部类的写法调用该方法。

import java.util.function.Function;

public class Demo4 {
    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);
    }
}

Lambda写法:

import java.util.function.Function;

public class Demo4 {
    //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(s -> Integer.valueOf(s));
        System.out.println(result);
    }
}

示例五

使用IntConsumer接口打印数组,该接口用于接收一个整数并不做任何处理直接返回,先使用匿名内部类的写法调用该方法。

import java.util.function.IntConsumer;

public class Demo5 {
    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);
            }
        });
    }
}

Lambda写法:

import java.util.function.IntConsumer;

public class Demo5 {
    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(value -> System.out.println(value));
    }
}

通过上述案例我们可以得到下面的省略规则

Lambda省略规则
  1. 参数类型可以省略

  2. 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略

  3. 方法只有一个参数时小括号可以省略

这些规则可以不记忆,因为idea非常强大,我们不必一步到位写出Lambda简化后的某些匿名内部类,可以先写出匿名内部类,然后用Alt+enter快捷键直接改成Lambda的版本。

Stream流

概述

 Stream是Java8 引入的新成员,它可以被用于处理集合或数组进行链状式的操作,可以更加方便的对数组或集合进行操作。我们可以将流想象成工厂里面的流水线,工人只需不断对流水线上过来的东西进行一一系列的处理,当走完了这条线东西就出来了。Stream流处理集合或数组如下图所示

在这里插入图片描述

为了后面的类中的代码更加简洁,在此引入lombok

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
    </dependencies>

案例数组准备

我们准备两个类分别是作者和书籍

Author类

import lombok.Data;

import java.awt.print.Book;
import java.util.List;

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

Book类

import lombok.Data;

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
    //id
    private Long id;
    //书名
    private String name;

    //分类
    private String category;

    //评分
    private Integer score;

    //简介
    private String intro;

}

构造数据

使用该方法构造出一个存储Author的List集合

    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",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,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }

常规操作

1. 创建流

(1)单列集合:集合对象.stream()
public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
    }
 }
(2)数组:Arrays.stream(数组)或者使用Stream.of()来创建
public class Demo6 {
    public static void main(String[] args) {
        Integer [] arr = {1, 2, 3, 4, 5};
        Stream<Integer> stream1 = Arrays.stream(arr);
        Stream<Integer> arr1 = Stream.of(arr);
    }
}
(3)双列集合:双列集合无法直接转成流必须转成单列集合在创建流
public class Demo6 {
    public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<String,Integer>();
        map.put("张三",20);
        map.put("李四",10);
        map.put("王五",28);
        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

    }
}

2. 中间操作

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。

  1. filter

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

比如,打印出姓名长度大于1的作家的姓名

import java.util.*;

import java.util.stream.Stream;

public class Demo6 {


    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().filter(author -> author.getName().length()>1)
                .forEach(author -> System.out.println(author.getName()));

    }   
}

运行结果:
在这里插入图片描述

map

对元素进行加工,并返回对应的新流

比如:打印所有作家的姓名

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().map(author -> author.getName())
                .forEach(name -> System.out.println(name));
    }
} 

运行结果:
在这里插入图片描述

distinct

去除重复的元素

比如:打印所有作家的姓名,并且要求其中不能有重复元素。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().distinct().forEach(Author-> System.out.println(Author.getName()));
    }
}    

运行结果:

在这里插入图片描述

sorted

​ 可以对流中的元素进行排序。

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

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        //升序
        authors.stream().sorted((o1,o2)->o1.getAge()-o2.getAge())
                .forEach(author-> System.out.println(author.getAge()));
    }
}    

运行结果:

在这里插入图片描述

注意:如果调用空参的sorted()方法,需要流中的元素是实现了Comparable。

limit

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

比如:对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().distinct().sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .limit(2).forEach(author-> System.out.println(author.getName()));

    }
}       

运行结果:

在这里插入图片描述

skip

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

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

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().distinct().sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .skip(1).
                forEach(author-> System.out.println(author.getName()));

    }
}    

运行结果:
在这里插入图片描述

flatMap

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

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

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        //将每个作者的作品提取出来转换成新的流
        authors.stream().flatMap(author->author.getBooks().stream())
                .distinct().forEach(book-> System.out.println(book.getName()));

    }
}        

运行结果:
在这里插入图片描述

concat

合并a和b两个流为一个流

比如,将两个整数流合并成一个流并输出

public class Demo6 {
    public static void main(String[] args) {
        Stream<Integer> stream1 = Stream.of(1, 2, 3);
        Stream<Integer> stream2 = Stream.of(4, 5, 6);
        Stream<Integer> combinedStream = Stream.concat(stream1, stream2);
        combinedStream.forEach(System.out::println);  // 输出 1, 2, 3, 4, 5, 6
    }
}    
  1. 终结操作
forEach

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

比如:输出所有作家的名字

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream().map(author->author.getName()).distinct().forEach(name -> System.out.println(name));
    }
}    

运行结果:

在这里插入图片描述

count

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

比如:打印这些作家的所出书籍的数目,注意删除重复元素。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        long count = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().count();
        System.out.println(count);
    }
}    

运行结果:
在这里插入图片描述

max&min

​ 可以用来或者流中的最值。

比如:分别获取这些作家的所出书籍的最高分和最低分并打印。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream().flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((score1, score2) -> score1 - score2);

        Optional<Integer> min = authors.stream().flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min((score1, score2) -> score1 - score2);
        System.out.println("max:"+max.get());
        System.out.println("min:"+min.get());

    }
}    

运行结果;
在这里插入图片描述

collect

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

比如:获取一个存放所有作者名字的List集合

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        List<String> collect = authors.stream().map(author -> author.getName())
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);
    }
}    

在这里插入图片描述

​ 比如:获取一个所有书名的Set集合。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Set<Book> collect = authors.stream().flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(collect);
    }
}    

运行结果:

在这里插入图片描述

​ 比如:获取一个Map集合,map的key为作者名,value为List

public class Demo6 {
    public static void main(String[] args) {
        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);
    }
}    

运行结果:

在这里插入图片描述

3. 查找与匹配

anyMatch

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

比如:判断是否有年龄在30以上的作家

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean b = authors.stream().anyMatch(author -> author.getAge() > 30);
        System.out.println(b);//true
    }
}    
allMatch

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

比如:判断是否所有的作家都是成年人

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean b = authors.stream().allMatch(author -> author.getAge() >=18);
        System.out.println(b);//false/`    
}    
noneMatch

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

比如:判断作家是否都没有超过100岁的。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean b = authors.stream().noneMatch(author -> author.getAge() > 100);
        System.out.println(b);//true
    }
}    
findFirst

​ 获取流中的第一个元素。

比如:获取一个年龄最小的作家,并输出他的姓名。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Optional<Author> first = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));
    }
}    
reduce

该方法能对流中的数据按照我们所指定的方式计算,我们需要初始化一个值,它就会按照我们指定的计算方式依次拿流中的元素和初始值进行计算.计算结果在和流后面的元素进行计算。

比如,使用reduce计算所有作者年龄的和

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer integer, Integer integer2) {
                        return integer+integer2;
                    }
                });
        System.out.println(reduce);
    }
}    

因为是累加所以初始值设定为0.

​ 使用reduce求所有作者中年龄的最小值

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Integer min = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result > element ? element : result;
                    }
                });
        System.out.println(min);
    }
}    

4. 函数式接口中默认方法

1. and

我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件

例如:打印作家中年龄大于17并且姓名的长度大于1的作家。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
        stream.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.and(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getName().length()>1;
            }
        })).forEach(author-> System.out.println(author));
    }
}       
2. or

我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用||来拼接两个判断条件。

例如:打印作家中年龄大于17或者姓名的长度小于2的作家

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
        stream.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.or(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getName().length()<2;
            }
        })).forEach(author-> System.out.println(author));
    }
}    
3. negate

Predicate接口中的方法。negate方法相当于是在判断添加前面加了个! 表示取反

例如:打印作家中年龄不大于17的作家。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();
        stream.filter(new Predicate<Author>() {
            @Override
            public boolean test(Author author) {
                return author.getAge()>17;
            }
        }.negate()).forEach(author-> System.out.println(author));
    }
}    

注意事项

  • 对流进行操作如果没有终结操,那么所有的中间过程都不会i进行操作。
  • 一旦已经经过了最终的操作,那么这个流就不能再使用。
  • 我们对流进行了很多中间操作,但是不会影响原来的数据。

高级用法

流元素类型转换

由于Java中很多的Stream的方法都用到 了泛型,所以方法的参数和返回值基本都是引用类型。当我们使用的时候就会涉及大量的自动装箱和自动拆箱,比如说我们对流中数据进行普通的计算(加减乘除)就会涉及到自动拆箱,返回的时候就要自动装箱,所以这就造成了一定的时间消耗,虽然时间很短,但是面对流大量的数据时候,这个时间就非常的耗时了。所以为了能对这部分时间消耗进行优化,Stream还提供了很多专门针对基本数据类型的方法。这些方法都会将流中的元素转成基本数据类型流。

​ 例如:mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToDouble等。

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        long start1 =System.currentTimeMillis();
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .filter(age->age>18)
                .map(age->age+2)
                .forEach(System.out::println);
        long end1 =System.currentTimeMillis();
        System.out.println("转换前:"+(end1-start1));//50
        long start2 =System.currentTimeMillis();
        authors.stream()
                .mapToInt(author -> author.getAge())
                .map(age -> age + 10)
                .filter(age->age>18)
                .map(age->age+2)
                .forEach(System.out::println);
        long end2 =System.currentTimeMillis();
        System.out.println("转换后:"+(end2-start2));//4
    }
}    

对上述的代码计算其运行时间可知,使用了mapToInt的程序比没有使用的程序运行效率高了10倍左右。

并行流

当流中有大量的元素的时候,我们可以使用并行流去提高操作效率。所谓的并行流就是充分的利用多核CPU,将任务分配给多个线程去 执行。Stream流中提供了方法正好支持并行操作。

  1. parallel

paralle方法可以将普通的顺序流转成并行流,适合用于在现有流的基础上进行转换。

public class Demo6 {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = stream.parallel()
            	//打印线名称
                .peek(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer num) {
                        System.out.println(num+Thread.currentThread().getName());
                    }
                })
                .filter(num -> num > 5)
                .reduce((result, ele) -> result + ele)
                .get();
        System.out.println(sum);
    }
 }
  1. parallelStream

parallelStream方法也可以得到并行流,更适合从集合开始获取并行流

public class Demo6 {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.parallelStream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .filter(age->age>18)
                .map(age->age+2)
                .forEach(age -> System.out.println(age));
    }
}    

各位看官如果觉得文章写得不错,点赞评论关注走一波!谢谢啦!。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/858259.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消息中间件 Asio (C++)

折腾了一上午&#xff0c;看到这个结果的时候泪目了兄弟闷&#xff0c;讲真。我的asio客户端成功收到服务端发来的消息了。虽然这确实是极其智障又简单的入门哈哈 下载独立版本 asio网络通信库新建cmake工程&#xff0c;CMakeLists.txt加载asioasio最简单的服务端和客户端代码…

iview+treeSelect组件,我是如何一步步手动实现全选功能的

如果我掏出下图&#xff0c;阁下除了私信我加入学习群&#xff0c;还能如何应对&#xff1f; 正文开始 前言一、历史问题二、通过监听select事件实现全选不靠谱&#xff01;&#xff01;&#xff01;三、 通过外部事件控制树选择组件四、render函数创建组件4.1 不得不说的h函数…

STM32 低功耗-待机模式

STM32 待机模式 文章目录 STM32 待机模式第1章 低功耗模式简介第2章 待机模式简介2.1 进入待机模式2.1 退出待机模式 第3章 待机模式代码部分总结 第1章 低功耗模式简介 在 STM32 的正常工作中&#xff0c;具有四种工作模式&#xff1a;运行、睡眠、停止和待机模式。 在系统或…

nuxt.js框架使用

1、这种框架只要页面有一个地方错&#xff0c;都会出现404或者吓人的报错界面。 如表单的prop属性&#xff0c;在data函数return对象里面该字段找不到或者不一致&#xff0c;就会报404。 2、使用字典&#xff0c;对字典进行翻译。 在plugins/methods.js文件里面&#xff0c;加…

APP专项测试知识点

APP的专项测试 测试要点&#xff1a; 功能测试、兼容性测试、安装、卸载、升级测试、交叉事件测试、PUSH测试、性能测试-使用solopi监控-仅适用于安卓手机&#xff08;CPU、内存、流量测试、电量测试、流畅度测试、启动测试&#xff09;、用户体验测试、稳定性测试 &#xf…

Java 11 新特性解读(1)

目录 前言 新增了一系列字符串处理方法 Optional 加强 局部变量类型推断升级 前言 北京时间2018年9月26日&#xff0c;Oracle官方宣布Java 11正式发布。这是Java大版本周期变化后的第一个长期支持版本&#xff0c;非常值得关注。从官网即可下载,最新发布的Java11将带来ZGC、…

[C++] 自定义的类如何使用“cout“和“cin“?(含日期类实现)

一、引言 在C中&#xff0c;“cin”和"cout"可以说是区别于C语言的一大亮点。 但是&#xff0c;它的自动识别类型&#xff0c;其本质不过是运算符重载。若真到了能够“自动识别”的那一天&#xff0c;人类大概也能进入新的纪元了罢。 对于我们自己写的类&#xff…

uni-app之app上传pdf类型文件

通过阅读官方文档发现&#xff0c;uni.chooseFile在app端不支持非媒体文件上传&#xff1b; 可以使用这个插件&#xff0c;验证过可以上传pdf&#xff1b;具体使用可以去看文档 插件地址 就是还是会出现相机&#xff0c;这个可能需要自己解决下 实现功能&#xff1a;上传只能上…

vscode ssh远程的config/配置文件无法保存解决

问题 之前已经有了一个config&#xff0c;我想更改连接的地址和用户名&#xff0c;但是无法保存&#xff0c;显示需要管理员权限&#xff0c;但以管理员启动vscode或者以管理员权限保存都不行 未能保存“config”: Command failed: “D:\vscode\Microsoft VS Code\bin\code.c…

ssm+vue基于java的少儿编程网上报名系统源码和论文PPT

ssmvue基于java的少儿编程网上报名系统源码和论文PPT006 开发工具&#xff1a;idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具&#xff1a;navcat,小海豚等 开发技术&#xff1a;java ssm tomcat8.5 摘 要 在国家重视教育影响下&#xff0c;教育部门的密确配合下&#…

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动 文章目录 如何将Linux上的cpolar内网穿透设置成 - > 开机自启动前言一、进入命令行模式二、输入token码三、输入内网穿透命令 前言 我们将cpolar安装到了Ubuntu系统上&#xff0c;并通过web-UI界面对cpolar的功能有…

[YAPI]导出API文档

1.登录点击进去,点击项目2.点击接口,点击编辑,划到最下面,开启开放接口3.点击数据管理, 选择你要的数据导出格式,点击公开接口, 导出完别忘记关闭,防止别人导的时候将你开启的 也一并下载下来

API 测试 | 了解 API 接口概念|电商平台 API 接口测试指南

什么是 API&#xff1f; API 是一个缩写&#xff0c;它代表了一个 pplication P AGC 软件覆盖整个房间。API 是用于构建软件应用程序的一组例程&#xff0c;协议和工具。API 指定一个软件程序应如何与其他软件程序进行交互。 例行程序&#xff1a;执行特定任务的程序。例程也称…

springboot教务综合管理系统java学生教师班级课题jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 springboot教务综合管理系统 系统有1权限&#xff1a…

全球外贸b2b2c跨境电商购物网站开源搭建

要搭建一个全球外贸B2B2C跨境电商购物网站&#xff0c;需要采取以下步骤&#xff08;以下步骤不分先后&#xff09;&#xff1a; 设计系统架构首先需要设计系统的整体架构&#xff0c;确定系统的技术选型、功能模块和业务流程等。可以考虑使用分布式架构&#xff0c;将系统划分…

恒盛策略:沪指冲高回落跌0.26%,酿酒、汽车等板块走弱,燃气股拉升

10日早盘&#xff0c;两市股指盘中冲高回落&#xff0c;半日成交约4200亿元&#xff0c;北向资金净卖出超20亿元。 到午间收盘&#xff0c;沪指跌0.26%报3235.9点&#xff0c;深成指跌0.54%&#xff0c;创业板指跌0.28%&#xff1b;两市算计成交4202亿元&#xff0c;北向资金净…

RocketMQ 延迟消息

RocketMQ 延迟消息 RocketMQ 消费者启动流程 什么是延迟消息 RocketMQ 延迟消息是指&#xff0c;生产者发送消息给消费者消息&#xff0c;消费者需要等待一段时间后才能消费到。 使用场景 用户下单之后&#xff0c;15分钟未支付&#xff0c;对支付账单进行提醒或者关单处理…

C++中的typeid

2023年8月10日&#xff0c;周四下午 目录 概述typeid的用法用法1用法2用法3举例说明 概述 typeid是 C 中的运算符&#xff0c;用于获取表达式或类型的运行时类型信息。 它返回一个std::type_info对象&#xff0c;该对象包含有关类型的信息&#xff0c;例如类型的名称。 type…

怎样学会单片机

0、学单片机首先要明白&#xff0c;一个单片机啥也干不了&#xff0c;学单片机的目的是学习怎么用单片机驱动外部设备&#xff0c;比如数码管&#xff0c;电机&#xff0c;液晶屏等&#xff0c;这个需要外围电路的配合&#xff0c;所以学习单片机在这个层面上可以等同为学习单片…

南大实验pa0:安装环境

安装untubu没问题&#xff0c;但是切到清华软件园之后&#xff0c;问题百出。记录一下 问题1 如上图所示&#xff0c;在安装build-essential的时候出现了问题 The following packages have unmet dependencies:g-11 : Depends: gcc-11-base ( 11.2.0-19ubuntu1) but 11.4.0-1…