菜鸟开发之Stream API中间件

本菜鸟在日常工作时,不是在对集合处理,就是在对集合操作的路上。看破红尘,遁入码门,一切都在修行。那对我来说代码的编写就很重要很重要,可是就是这集合的处理操作让人头疼不已,怎么处理集合会显得更高级,操作更“装逼”呢,下面就是本菜鸟学来在日常慢慢使用的“神器”。

Java8新特性中的Stream API ,便是简洁高效处理集合数据的方式, 不仅可读性较高, 且特别在数据的过滤、转换、聚合时使得操作更简单方便快捷。Stream API根据平时的需求开发中大概两方面,一个作为中间操作使用,一个是最终使用。

有的人肯定直接用不想底层,不在做更多的介绍,底层需要日后平时没事更多学习了解。

一、中间使用

1、过滤筛选:filter

根据指定条件过滤元素,只保留符合条件的,其中Lambda 表达式 s -> s.contains("大")用于判断字符串是否包含字符"大"。

List<String> tempList = Arrays.asList("刘一手", "杜子腾", "林大蛋", "Ekko");
List<String> resList = tempList.stream()
                        .filter(s -> s.contains("大"))
                        .collect(Collectors.toList()); 
输出:[林大蛋]

但collect(Collectors.toList())是最终操作

2、拼接赋值:map(函数)

对每个元素执行映射操作, 将元素转换成另一种类型。

List<String> tempList = Arrays.asList("刘一手", "杜子腾", "林大蛋", "Ekko");
    List<String> resList = tempList.stream()
            .map(s -> "姓名: " + s)
            .collect(Collectors.toList());
输出:[姓名: 刘一手, 姓名: 杜子腾, 姓名: 林大蛋, 姓名: Ekko]

.map(s ->"姓名: " + s)是简写,详细如下:

.map(s -> {return "姓名:" + s;})

3、数据聚合:flatMap(函数)

可以将每个元素映射成一个 Stream,把所有生成的 Stream 合并成一个新的Stream。

@Data
static class Personnel {
    // 人员姓名
    private String name;
    // 人员标签
    private List<String> tagList;

    public Personnel(String name, List<String> tagList) {
        this.name = name;
        this.tagList = tagList;
    }
}
public static void main(String[] args) {
    Personnel personA = new Personnel("张三", Arrays.asList("抽烟", "喝酒", "烫头"));
    Personnel personB = new Personnel("李斯", Arrays.asList("编码", "喝酒", "踢足球"));
    List<Personnel> personnelList = Arrays.asList(personA, personB);
    personnelList.stream()
            .flatMap(p -> p.getTagList().stream())
            .forEach(s -> System.out.print(s + " "));
}
输出:抽烟 喝酒 烫头 编码 喝酒 踢足球 

上面创建静态内部类,其中聚合类中的集合数据,后把 List<Personnel> 中的 tagList 聚合后进行处理。

4、规则排序:sorted()

元素进行排序,默认按照自然顺序,也可自定义的Comparator来指定排序规则。

public class SortedTest {
    public static void main(String[] args) {
        List<Integer> numList = Arrays.asList(10, 20, 18, 300, 30, 2);
        // ① 默认排序
        List<Integer> orderList = numList.stream()
                .sorted()
                .collect(Collectors.toList());
        System.out.printf("① 默认排序: %s%n", orderList);
        // ② 自定义排序
        List<Integer> orderDescList = numList.stream()
                .sorted((x, y) -> {
                    return y.compareTo(x);
                })
                .collect(Collectors.toList());
        System.out.printf("② 自定义排序: %s%n", orderDescList);
    }
}
输出:
① 默认排序: [2, 10, 18, 20, 30, 300]
② 自定义排序: [300, 30, 20, 18, 10, 2]

如果你需要自定义排序规则,可以在自定义的类中实现Comparator接口,并使用compare方法,如下所示:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
 
public class CustomComparatorExample {
    public static void main(String[] args) {
        List<Fruit> fruits = Arrays.asList(new Fruit("apple", 100), 
                                            new Fruit("banana", 200), 
                                            new Fruit("cherry", 150));
 
        // 使用自定义Comparator进行排序
        List<Fruit> sortedFruits = fruits.stream()
                                         .sorted(Comparator.comparing(Fruit::getWeight))
                                         .collect(Collectors.toList());
        // 输出排序后的列表
        sortedFruits.forEach(System.out::println);
    }
}
 
class Fruit {
    private String name;
    private int weight;
 
    public Fruit(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }
 
    public String getName() {
        return name;
    }
 
    public int getWeight() {
        return weight;
    }
 
    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", weight=" + weight +
                '}';
    }
}

在这个例子中,Fruit类有一个getWeight方法,我们使用Comparator.comparing来创建一个自定义的Comparator,然后根据水果的重量进行排序。(提示:AI自动生成,仅供参考)

5、同数去重:distinct()

确保每个元素唯一性,输出:[1, 2, 3]

List<Integer> numList = Arrays.asList(1,1,1,1,2,3,2,2);
        List<Integer> distinctList = numList.stream()
                .distinct()
                .collect(Collectors.toList());

6、限制取值:limit(long n)

返回一个最大包含前n个元素的新Stream,输出:[1, 2, 3, 4]

  List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8);
        List<Integer> limitList = numList.stream()
                .limit(4)
                .collect(Collectors.toList());

7、跳过丢弃:skip(long n)

跳过前n个元素,输出:[7, 8]

List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        List<Integer> skipList = numList.stream()
                .skip(numList.size() - 2)
                .collect(Collectors.toList());

8、调试记录

对每个元素执行一个操作,同时保持Stream的流,可以用于调试或记录Stream中的元素

List<Integer> numList = Arrays.asList(5, 6, 7, 8);
        List<Integer> resList = numList.stream()
                .peek(System.out::println)
                .filter(s -> s == 5)
                .peek(s -> System.out.printf("过滤后的:%d%n", s))
                .collect(Collectors.toList());
输出:
5
过滤后的:5
6
7
8

二、最终操作

1、循环遍历:forEach(Consumer)

对Stream中的每个元素执行指定的操作,接收一个Consumer(消费者函数)作为参数。它通常用于对Stream中的元素进行输出或执行某些操作,但不会返回任何结果。

 // 给公司工资普涨 500
        List<Integer> salaryList = Arrays.asList(12000, 20000, 30000, 4000);
        salaryList.stream()
                .peek(s -> System.out.print("工资普涨前:" + s))
                .map(s -> s + 500)
                .forEach(s -> {
                    System.out.println("--工资普涨后:" + s);
                });

        创建一个工资集合,通过 stream() 方法转换为 Stream 流,中间操作 peek() 方法记录转换前的元素值,后 map() 方法给元素进行转换操作,最后通过,forEach() 方法进行遍历。

输出:

工资普涨前:12000--工资普涨后:12500
工资普涨前:20000--工资普涨后:20500
工资普涨前:30000--工资普涨后:30500
工资普涨前:4000--工资普涨后:4500

2、 数据收集:collect(Collector)

可将元素收集到List、Set、Map等容器中

 public static void main(String[] args) {
        List<User> userList = Arrays.asList(new User("张三", 2000.5),
                new User("李斯", 11000.5),
                new User("王二", 12000.5),
                new User("张六", 32000.5),
                new User("赵公子", 1000000.0));
        Map<String, Double> userSalaryMap = userList.stream()
                .collect(Collectors.toMap(User::getName, User::getSalary));
        userSalaryMap.forEach((k, v) -> {
            System.out.printf("姓名:%s,工资:%.2f%n", k, v);
        });
    }

    @Data
    @AllArgsConstructor
    static class User {
        private String name;
        private Double salary;
    }
输出:
姓名:张三,工资:2000.50
姓名:赵公子,工资:1000000.00
姓名:张六,工资:32000.50
姓名:李斯,工资:11000.50
姓名:王二,工资:12000.50

collect() 方法把元素归集,利用 Collectors.toMap() 收集器转换为 Map ,内部接收遍历每个元素。

Collectors.toMap(User::getName, User::getSalary)是简写,详细的如下:

Collectors.toMap(s -> s.getName(), s -> s.getSalary())

3、最大最小值:min/ max (Comparator)

min,最小值;max,最大值;comparator参数用于确定元素的顺序,以便找到最小值

public static void main(String[] args) {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用min()找到最小值
        Optional<Integer> minOptional = integerStream.min(Integer::compareTo);
        if (minOptional.isPresent()) {
            System.out.println("最小值为: " + minOptional.get());
        } else {
            System.out.println("流为空.");
        }

        // 重新创建一个整数流,因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用max()找到最大值
        Optional<Integer> maxOptional = newIntegerStream.max(Integer::compareTo);
        if (maxOptional.isPresent()) {
            System.out.println("最大值为: " + maxOptional.get());
        } else {
            System.out.println("流为空.");
        }
    }
输出:
最小值为: 1
最大值为: 8

一旦流被消耗就不能再次使用,因此在找到最小值后重新创建了一个整数流来找到最大值。

 4、计算个数:count()

 public static void main(String[] args) {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用count()计算流中的元素个数
        long count = integerStream.count();

        // 输出元素个数
        System.out.println("元素数量: " + count);
    }

输出:元素数量: 5

 5、是否满足:anyMatch / allMatch / noneMatch (Predicate)

anyMatch:检查流中是否存在至少一个元素满足给定的条件

allMatch:检查流中的所有元素是否都满足给定的条件

noneMatch:检查流中是否所有元素都不满足给定的条件

public static void main(String[] args) {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用anyMatch()检查是否存在元素大于5
        boolean anyGreaterThan5 = integerStream.anyMatch(num -> num > 5);
        System.out.println("是否存在元素大于 5 ?" + anyGreaterThan5);

        // 重新创建一个整数流,因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用allMatch()检查是否所有元素都小于10
        boolean allLessThan10 = newIntegerStream.allMatch(num -> num < 10);
        System.out.println("所有元素都小于10 ? " + allLessThan10);

        // 重新创建一个整数流,因为流已被消耗
        Stream<Integer> newestIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用noneMatch()检查是否没有元素等于10
        boolean noneEqualTo10 = newestIntegerStream.noneMatch(num -> num == 10);
        System.out.println("是否没有元素等于 10 ? " + noneEqualTo10);
    }

输出:

是否存在元素大于 5 ?true
所有元素都小于10? true
是否没有元素等于 10 ? true

 6、findFirst() / findAny()

findFirst():流中查找第一个满足条件的元素

findAny():流中查找任意一个满足条件的元素

public static void main(String[] args) {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用findFirst()找到第一个元素
        Optional<Integer> firstElementOptional = integerStream.findFirst();
        if (firstElementOptional.isPresent()) {
            System.out.println("发现第一个元素: " + firstElementOptional.get());
        } else {
            System.out.println("流为空!");
        }

        // 重新创建一个整数流,因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用findAny()找到任意一个元素
        Optional<Integer> anyElementOptional = newIntegerStream.findAny();
        if (anyElementOptional.isPresent()) {
            System.out.println("找到任意一个元素: " + anyElementOptional.get());
        } else {
            System.out.println("流为空!");
        }
    }

输出:

发现第一个元素: 1
找到任意一个元素: 1

程序员鱼丸,以上学习主要来自这个位大佬。

革命尚未成功,本菜鸟仍需努力

三、Java Stream类常见用法

1、基本转换

List<String> nameList = students.stream()
	.map(Student::getName)
	.collect(Collectors.toList());

2、过滤加基本转换

List<String> above90Names = students.stream()
	.filter(t->t.getScore()>90)
	.map(Student::getName)
	.collect(Collectors.toList());

3、中间操作distinct

List<String> list = Arrays.asList(new String[]{"abc", "def", "hello", "Abc"});
List<String> retList = list.stream()
	.filter(s->s.length()<=3)
	.map(String::toLowerCase)
	.distinct()
	.collect(Collectors.toList());

4、中间操作sorted

//返回 对象集合以类属性一升序排序
list.stream().sorted(Comparator.comparing(类::属性一));

//返回 对象集合以类属性一降序排序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序

//返回 对象集合以类属性一升序 属性二升序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));

//返回 对象集合以类属性一降序 属性二升序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序

//返回 对象集合以类属性一降序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序

//返回 对象集合以类属性一升序 属性二降序 注意两种写法
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序

Comparator.comparing(类::属性一).reversed();

Comparator.comparing(类::属性一,Comparator.reverseOrder());

两种排序是完全不一样的,一定要区分开来:1是得到排序结果后再排序,2是直接进行排序,很多人会混淆导致理解出错,2更好理解,建议使用2

 5、中间操作skip/limit

List<Student> list = students.stream()
	.sorted(Comparator.comparing(Student::getScore).reversed())
	.skip(2).limit(3)
	.collect(Collectors.toList());

6、中间操作map ToLong/ToInt/ToDouble

double sum = students.stream().mapToDouble(Student::getScore).sum();

 7、终端操作max/min

Student student = students.stream().max(Comparator.comparing(Student::getGrade)).get();

Student student = students.stream().min(Comparator.comparing(Student::getGrade).reversed()).get();

8、容器收集toMap

Map<String, Double> nameScoreMap = students.stream().collect(Collectors.toMap(Student::getName, Student::getScore, (oldValue, value)->value));

Map<String, Student> byIdMap = students.stream().collect(Collectors.toMap(Student::getId, Function.identity(), (oldValue, value)->value));

Map<String, Integer> strLenMap = Stream.of("abc", "hello", "abc").collect(Collectors.toMap(Function.identity(), t->t.length(), (oldValue, value)->value));

9、分组

//将学生流按照年级进行分组
Map<String, List<Student>> groups = students.stream().collect(Collectors.groupingBy(Student::getGrade));

//统计每个年级的学生个数
Map<String, Long> gradeCountMap = students.stream().collect(groupingBy(Student::getGrade, counting()));

//统计一个单词流中每个单词的个数,按出现顺序排序
Map<String, Long> wordCountMap = Stream.of("hello", "world", "abc", "hello").collect( groupingBy(Function.identity(), LinkedHashMap::new, counting()));

//对学生按年级分组,得到学生名称列表
Map<String, List<String>> gradeNameMap = students.stream().collect(groupingBy(Student::getGrade, mapping(Student::getName, toList()))); 

//将学生按年级分组,分组内的学生按照分数由高到低进行排序
Map<String, List<Student>> gradeStudentMap = students.stream().collect(groupingBy(Student::getGrade, collectingAndSort(toList(), Comparator.comparing(Student::getScore).reversed())));

//将学生按年级分组,分组后,每个分组只保留不及格的学生(低于60分)
Map<String, List<Student>> gradeStudentMap = students.stream()
.collect(groupingBy(Student::getGrade, collectingAndFilter(toList(), t->t.getScore()<60)));

hellosc01感谢前辈,嘿哈!!!

以后再完善

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值