Java8 - Stream API 处理集合数据

news/2024/7/24 11:00:30 标签: java

Java 8的Stream API提供了一种功能强大的方式来处理集合数据,以函数式和声明式的方式进行操作。Stream API允许您对元素集合执行操作,如过滤、映射和归约,以简洁高效的方式进行处理。

下面是Java 8 Stream API的一些关键特性和概念:

① 创建流:您可以从各数据源创建流,如集合、数组或I/O通道。

② 中间操作:Stream提供了一组中间操作,可以链接在一起对数据进行转换或过滤。一些常见的中间操作包括filter、map、flatMap、distinct、sorted和limit。

③ 终端操作:终端操作用于生成结果或产生副作用。终端操作的示例包括forEach、collect、reduce、min、max和count。

④ 惰性求值:Stream支持惰性求值,这意味着中间操作只有在调用终端操作时才会执行。这样可以高效处理大型数据集。

⑤ 并行处理:Stream API还支持并行处理,允许您利用多核处理器加速对大型数据集的操作。您可以使用parallel或parallelStream方法将顺序流转换为并行流。

01. map 函数

通过使用map函数,我们可以对流中的每个元素进行转换操作,从而得到一个新的流。这种转换可以是类型转换、属性提取、计算等。

java">@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
    private String name;
    private Integer age;
}
java">@Test
public void test0() {
    List<Person> list = Arrays.asList(
        new Person("zhangsan", 10),
        new Person("zhangsan", 11),
        new Person("wangwu", 12)
    );

    //(1) map函数将list中的每个Person对象映射为其name属性,并使用collect()方法将新的流收集到一个新的列表nameList中
    List<String> nameList = list.stream().map(person -> {
        return person.getName();
    }).collect(Collectors.toList());
    System.out.println(nameList);  // [zhangsan, zhangsan, wangwu]

    //(2) map函数将list中的每个Person对象映射为其年龄,并将映射后的结果收集到一个新的整数列表ageList中
    List<Integer> ageList = list.stream().map(Person::getAge).collect(Collectors.toList());
    System.out.println(ageList);

    //(3) map函数将list中的每个Person对象映射为其年龄加1后的整数,并使用collect方法将映射后的结果收集到一个新的列表ageList1中
    List<Integer> ageList1 = list.stream().map(person -> {
        return person.getAge() + 1;
    }).collect(Collectors.toList());

    //(4) map函数将list中的每个Person对象的名称转换为大写形式,并将结果收集到一个新的字符串列表uppercaseNames中。
    List<String> uppercaseNames = list.stream().map(person -> {
        return person.getName().toUpperCase();
    }).collect(Collectors.toList());
}

02. mapToInt函数

mapToInt是Stream接口提供的一个方法,用于将流中的元素映射为int类型的值。它接受一个ToIntFunction参数,用于指定如何将流中的元素映射为int类型的值。

java">@Test
public void test14() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

    // map 函数
    Stream<Integer> stream = numbers.stream().map(n -> n * n);
    List<Integer> list1 = stream.collect(Collectors.toList());
    System.out.println(list1);

    // mapToInt 函数
    IntStream intStream = numbers.stream().mapToInt(n -> n * n);
    int sum = intStream.sum(); // 求和
    // OptionalDouble average = intStream.average(); // 平均值
    // OptionalInt max = intStream.max(); // 最大值
    // OptionalInt min = intStream.min(); // 最小值
}

map和mapToInt都是Stream接口提供的方法,用于对流中的元素进行映射转换。它们的区别在于返回值的类型和适用范围:

① map方法接受一个Function参数,用于指定如何将流中的元素映射为其他类型的值。它返回一个新的流,其中包含映射后的值。返回的流是一个泛型流,即Stream,其中R是映射后的值的类型。

② mapToInt方法也接受一个Function参数,用于指定如何将流中的元素映射为int类型的值。它返回一个新的IntStream,其中包含映射后的int值。返回的流是一个特殊的流,专门用于处理int类型的值,提供了更高效的操作和更少的内存消耗。

需要注意的是,IntStream提供了一些特殊的操作,例如sum、average、max、min等,这些操作只适用于IntStream,而不适用于泛型流Stream。如果需要对映射后的值进行这些特殊操作,应该使用mapToInt方法。

除了mapToInt方法,Stream接口还提供了其他一些类似的映射方法,如mapToLong和mapToDouble,用于将流中的元素映射为long类型和double类型的值。

03. filter 函数

通过使用filter函数,我们可以根据指定的条件过滤出流中满足条件的元素,从而得到一个新的流。这种过滤可以是基于元素的某个属性、某种关系或其他条件。

java">@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
    private String name;
    private Integer age;
}
java">@Test
public void test1() {
    List<Person> list = Arrays.asList(
        new Person("zhangsan", 10),
        new Person("zhangsan", 11),
        new Person("wangwu", 12)
    );

    // filter函数过滤出列表中Person对象的name为zhangsan的元素,最后使用collect方法将过滤后的结果收集到一个新的列表中。
    List<Person> list1 = list.stream().filter(person -> {
        return person.getName().equals("zhangsan");
    }).collect(Collectors.toList());
    System.out.println(list1); // [Person(name=zhangsan, age=10), Person(name=zhangsan, age=11)]

    // 简洁写法
    List<Person> list2 = list.stream().filter(person -> person.getName().equals("zhangsan")).collect(Collectors.toList());

    // filter函数过滤出列表中Person对象的age为偶数的元素,最后使用collect方法将过滤后的结果收集到一个新的列表中。
    List<Person> list3 = list.stream().filter(person -> person.getAge() % 2 == 0).collect(Collectors.toList());
    System.out.println(list3); // [Person(name=zhangsan, age=10), Person(name=wangwu, age=12)]
}

04. flatMap 函数

flatMap函数是一种中间操作,用于对流中的每个元素进行映射操作,并将映射结果扁平化为一个新的流。

① flatMap函数将每个子列表映射为一个流,并将这些流扁平化为一个新的流:

java">@Test
public void test2() {
    // 首先创建一个嵌套的整数列表nestedList,其中包含了三个子列表。
    List<List<Integer>> nestedList = Arrays.asList(
        Arrays.asList(1, 2, 3),
        Arrays.asList(4, 5, 6),
        Arrays.asList(7, 8, 9)
    );

    // flatMap函数将每个子列表映射为一个流,并将这些流扁平化为一个新的流,最后使用collect方法将扁平化后的结果收集到一个新的整数列表flattenedList中。
    List<Integer> flattenedList = nestedList.stream().flatMap(list->{
        return list.stream();
    }).collect(Collectors.toList());

    // 简洁写法
    List<Integer> collect = nestedList.stream().flatMap(List::stream).collect(Collectors.toList());
    System.out.println(collect);
}

② 使用flatMap函数将list中每个Person对象的ids列表扁平化为一个新的流:

java">@NoArgsConstructor
@AllArgsConstructor
@Data
public class Person {
    List<Integer> ids;
    private String name;
    private Integer age;
    
    public Person(String name,Integer age){
        this.name = name;
        this.age = age;
    }
}
java">@Test
public void test3() {
    Person qo1 = new Person("zhangsan",10);
    qo1.setIds(Arrays.asList(1,2,3));
    Person qo2 = new Person("zhangsan",11);
    qo2.setIds(Arrays.asList(4,5,6));
    Person qo3 = new Person("wangwu",12);
    qo3.setIds(Arrays.asList(7,8,9));

    List<Person> list = new ArrayList<>();
    list.add(qo1);
    list.add(qo2);
    list.add(qo3);

    List<Integer> list1 = list.stream().flatMap(Person -> {
        return Person.getIds().stream();
    }).collect(Collectors.toList());
    System.out.println(list1); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

    List<List<Integer>> list2 = list.stream().map(Person -> {
        return Person.getIds();
    }).collect(Collectors.toList());
    System.out.println(list2); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

    List<Integer> list3 = list.stream().flatMap(Person -> {
        return Optional.ofNullable(Person.getIds()).orElse(new ArrayList<>()).stream();
    }).collect(Collectors.toList());
    System.out.println(list3); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
}

05. distinct 函数

distinct函数是一种中间操作,用于去除流中的重复元素,保留唯一的元素。它会根据元素的equals方法进行比较来判断元素是否重复。

java">@Test
public void test4() {
    List<Integer> list = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5);
    List<Integer> list1 = list.stream().distinct().collect(Collectors.toList());
    System.out.println(list1);
}

如果想要根据对象的属性进行去重,您可以使用Java 8的Stream API结合distinct函数和自定义的equals和hashCode方法来实现。

java">@NoArgsConstructor
@AllArgsConstructor
@Data
public
class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
java">@Test
public void test5() {
    List<Person> list = Arrays.asList(
        new Person("zhangsan", 10),
        new Person("zhangsan", 10),
        new Person("wangwu", 12)
    );

    List<Person> collect = list.stream().distinct().collect(Collectors.toList());
    System.out.println(collect); // [Person(name=zhangsan, age=10), Person(name=wangwu, age=12)]
}

06. sorted 函数

sorted函数是一种中间操作,用于对流中的元素进行排序。它可以按照自然顺序或者通过自定义的比较器进行排序。

① sorted():按照自然顺序对流中的元素进行排序。

java">@Test
public void test6() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    List<Integer> sortedNumbers = numbers.stream()
        .sorted()
        .collect(Collectors.toList());
    System.out.println(sortedNumbers); // [1, 2, 3, 5, 8]
}

② sorted(Comparator<? super T> comparator):根据自定义的比较器对流中的元素进行排序。

java">@Test
public void test7() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    List<Integer> sortedNumbers = numbers.stream()
        .sorted(new Comparator<Integer>() {
            @Override
            public int compare(Integer obj1, Integer obj2) {
                // 倒序排序
                return obj2-obj1;
            }
        })
        .collect(Collectors.toList());
    System.out.println(sortedNumbers); // [8, 5, 3, 2, 1]

    // 降序排序
    List<Integer> collect = numbers.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
}

07. limit 函数

limit 函数是一种中间操作,用于截取流中的前n个元素。它会返回一个新的流,其中包含原始流中的前n个元素。

java">@Test
public void test8() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    // 截取列表中的前3个元素
    List<Integer> list1 = numbers.stream().limit(3).collect(Collectors.toList());
    System.out.println(list1); // [5, 2, 8]

    // 对列表中的元素排序,再截取列表中的前3个元素
    List<Integer> list2 = numbers.stream().sorted().limit(3).collect(Collectors.toList());
    System.out.println(list2); // [1, 2, 3]
}

08. min 函数

min函数是一种终端操作,用于找到流中的最小元素。它接受一个Comparator函数作为参数,用于确定元素的顺序。通过使用min函数,我们可以方便地找到流中的最小元素。这对于需要找到最小值或根据某个属性进行排序的场景非常有用。

java">@Test
public void test9() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    // min函数并传入比较器,找到流中的最小值
    Optional<Integer> optional = numbers.stream().min(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            // 正序排序
            return o1 - o2;
        }
    });

    // 简洁写法
    Optional<Integer> optional1 = numbers.stream().min(Integer::compareTo);

    // 使用Optional类来处理可能为空的结果,并打印输出最小值
    if(optional.isPresent()){
        System.out.println(optional.get()); // 1
    }else {
        System.out.println("Stream is empty");
    }
}

@Test
public void test10() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    // min函数并传入比较器
    Optional<Integer> optional = numbers.stream().min(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            // 倒叙排序
            return o2-o1;
        }
    });

    // 使用Optional类来处理可能为空的结果
    if(optional.isPresent()){
        System.out.println(optional.get()); // 8
    }else {
        System.out.println("Stream is empty");
    }
}

09. max 函数

max函数是一种终端操作,用于找到流中的最大元素。它接受一个Comparator函数作为参数,用于确定元素的顺序。

java">@Test
public void test11() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    // max函数并传入比较器
    Optional<Integer> optional = numbers.stream().max(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            // 正序排序
            return o1-o2;
        }
    });

    // 简洁写法
    Optional<Integer> optional1 = numbers.stream().max(Integer::compareTo);

    // 使用Optional类来处理可能为空的结果
    if(optional.isPresent()){
        System.out.println(optional.get()); // 8
    }else {
        System.out.println("Stream is empty");
    }
}

10. count 函数

count函数是一种终端操作,用于计算流中的元素数量。它返回一个long类型的值,表示流中的元素个数。

java">@Test
public void test12() {
    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 3);
    System.out.println(numbers.stream().count()); // 5
}

11. groupby 函数

groupBy函数,用于对流中的元素进行分组。groupBy函数接受一个Function参数,用于指定分组的依据。它将流中的元素按照该函数的返回值进行分组,并返回一个Map对象,其中键是分组的依据,值是属于该分组的元素列表。

java">@Test
public void test12() {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    // 使用 n -> n % 2 == 0 ? "偶数" : "奇数"作为分组的依据,将整数列表按照奇偶数进行分组。
    // 最终得到的groups对象是一个Map,其中键是"奇数"和"偶数",值是属于该分组的整数列表。
    Map<String, List<Integer>> groups = numbers.stream().collect(Collectors.groupingBy(n -> n % 2 == 0 ? "偶数" : "奇数"));
    System.out.println(groups); // {偶数=[2, 4, 6, 8, 10], 奇数=[1, 3, 5, 7, 9]}
}

还可以使用groupBy函数按照对象的属性进行分组。

java">@Test
public void test13() {
    List<Person> list = Arrays.asList(
            new Person("zhangsan", 10),
            new Person("lisi", 10),
            new Person("wangwu", 12)
    );
    Map<Integer, List<Person>> map = list.stream().collect(Collectors.groupingBy(person -> person.getAge()));
    // Map<Integer, List<Person>> map = list.stream().collect(Collectors.groupingBy(Person::getAge));
    System.out.println(map); // {10=[Person(name=zhangsan, age=10), Person(name=lisi, age=10)], 12=[Person(name=wangwu, age=12)]}
}

http://www.niftyadmin.cn/n/5546967.html

相关文章

Spring Boot项目中JPA操作视图会改变原表吗?

一直有一种认识就是:使用JPA对视图操作,不会影响到原表。 直观的原因就是视图是一种数据库中的虚拟表,它由一个或多个表中的数据通过SQL查询组成。视图不包含数据本身,而是保存了一条SQL查询,这条查询是用来展示数据的。 但是在实际项目种的一个场景颠覆和纠正了这个认识…

Mini-L-CTF-2022 minispringboot Thymeleaf模板注入 spel的绕过

Mini-L-CTF-2022 minispringboot Thymeleaf模板注入 spel的绕过 就是一个低版本的Thymeleaf注入 漏洞点 public class MainController {GetMapping({"/{language}"})public String test(PathVariable(name "language") String language, RequestParam(…

0703_ARM7

练习&#xff1a; 封装exti&#xff0c;cic初始化函数 //EXTI初始化 void hal_key_exti_init(int id,int exticr,int mode){//获取偏移地址int address_offset (id%4)*8;//获取寄存器编号int re_ser (id/4)1;//printf("address_offset%d,re_ser%d\n",address_o…

【竞技宝】欧洲杯:西班牙进四强,队长做出让球迷意外的重要决定

西班牙是本届欧洲杯最具冠军相的球队,因为球队从小组赛开始就表现强势。西班牙进攻中能多点开花,防守端则是滴水不漏,让很多球迷和媒体都眼前一亮。另外,西班牙队打法非常好看,不管是小组赛还是淘汰赛从来不苟着踢。所以,西班牙就吸引了一批新球迷关注和青睐,认为斗牛士军团只要…

【实战场景】记一次UAT jvm故障排查经历

【实战场景】记一次UAT jvm故障排查经历 开篇词&#xff1a;干货篇&#xff1a;1.查看系统资源使用情况2.将十进制进程号转成十六进制3.使用jstack工具监视进程的垃圾回收情况4.输出指定线程的堆内存信息5.观察日志6.本地环境复现 总结篇&#xff1a;我是杰叔叔&#xff0c;一名…

如何提升美国Facebook直播的整体体验?

Facebook作为全球最大的社交媒体平台之一&#xff0c;提供了直播功能&#xff0c;用户可以实时分享生活、见解和创意。许多商家通过美国Facebook直播来获取更多客户&#xff0c;但直播时可能会遇到网络卡顿的问题&#xff0c;导致观看体验不佳。本文将探讨如何解决这个问题&…

AI 图像处理 --CodeFormer 简介

CodeFormer是一款基于深度学习技术&#xff0c;特别是利用自动编码器和VQGAN&#xff08;Vector Quantised Generative Adversarial Network&#xff09;进行人脸修复和视频增强的强大人工智能工具。它通过高分辨率重建和细节修复&#xff0c;显著提升了图像和视频的质量和视觉…

计算机单位换算,网络传输速度换算,图片大小计算

1.计算机单位换算 二进制系统中&#xff0c;最基本的单位是比特&#xff08;bit&#xff0c;简写为b&#xff09;&#xff0c;表示一个二进制位&#xff0c;可以是0或1。也是我们常说的位字节&#xff08;Byte&#xff0c;简写为B&#xff09;&#xff1a;1 Byte 8 bits。字节…