Stream流+不可变集合

不可变集合

  • 创建不可变集合:数据不能修改,防御性拷贝到不可变集合中;被不可信库调用时,安全。
  • 在List Set Map 接口中都存在静态方法of->获取不可变集合-->不能添加,删除,修改(只读)
List<String> list = List.of("","","");
//remove add set xxx都不可
Set<String> set = Set.of("","","");//无索引
//获取一个不可变set集合 参数保证唯一性 
Map<String,String> map = Map.of("key","value");
//键不能重复  参数有上限(10个)
//参数多出10个时->ofEntries jdk10->copyOf
------------方一---------------
HashMap<String,String> map = new HashMap<>();
    map.put("123","123");//put超过十个
    //获取所有键值对象 Entry对象
    Set<Map.Entry<String,String>>entries = map.entrySet();
    //把entries变成一个数组 类型时entry对象
    //toArray方法会比较集合的长度与数组的长度
    //集合长度>数组长度 根据实际集合数据个数 新建数组,反之<= 直接用 多出来的为nul
    Map.Entry[] arr = entires.toArray(new Map.Entry[0]);
    Map map1 = Map.ofEntries(arr);
    //不可变创完
---------------方二------------------
    //简化
    Map<Object,Object> map1 = Map.ofEntries(map.entrySet().toArray(new Map.Entry[0]));
---------------方三------------------
    //jdk10
    Map<String,String> map1 = mapMap.copyOf(map);

Stream

简介

结合Lambda表达式 简化集合、数组的操作

特性:

  1. Stream 自己不会存储元素。

  2. Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

  3. Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结果。

  4. Stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。

流式处理

eg:

比如希望对一个包含整数的集合中筛选出所有的偶数,并将其封装成为一个新的List返回

List<Integer> evens = new ArrayList<>();
for (final Integer num : nums) {
    if (num % 2 == 0) {
        evens.add(num);
    }
}

通过java8的流式处理,将代码简化为:

List<Integer> evens = nums.stream().filter(num -> num % 2 == 0).collect(Collectors.toList());
------eg2--------
    ArrayList<String> list = new ArrayList<>();
        list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3 ).forEach(name -> System.out.println(name));

解释:stream()操作将集合转换成一个流,filter()执行我们自定义的筛选处理,这里是通过lambda表达式筛选出所有偶数,最后我们通过collect()对结果进行封装处理,并通过Collectors.toList()指定其封装成为一个List集合返回。

一个流式处理可以分为三个部分:转换成流、中间操作、终端操作

以集合为例,一个流式处理的操作我们首先需要调用stream()函数将其转换成流,然后再调用相应的中间操作达到我们需要对集合进行的操作,比如筛选、转换等,最后通过终端操作对前面的结果进行封装,返回我们需要的形式。

步骤:

  1. 得到stream流 放数据

    获取方式方法名说明
    单列集合default Stream<E> stream()Collection中的默认方法
    双列集合无(勇keySet or entrySet 先变成单列)无法直接使用stream流
    数组public static <T> Stream <T> stream (T[] array)Arrays工具类中的静态方法
    一堆零散数据public static <T> Stream <T> of (T...values)Stream接口中的静态方法

    单列集合:

             ArrayList<String> list = new ArrayList<>();
            Collections.addAll(list,"a","b","c","d","e","f");
            //获取一条流水线 将集合数据放流水线上
            /*Stream<String> stream = list.stream();
            stream.forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    // s 一次表示流水线上的每一个数据
                    System.out.println(s);
                }
            });*/
            list.stream().forEach(s-> System.out.println(s));

    双列集合:

             //创建双列集合
            HashMap<String, Integer> hm = new HashMap<>();
            hm.put("aaa",1111);
            hm.put("bbb",2222);
            hm.put("ccc",3333);
            hm.put("mmm",4444);
            //获取stream流
            //打印所有键
            hm.keySet().stream().forEach(s-> System.out.println(s));
            //打印所有键值对
            hm.entrySet().stream().forEach(s-> System.out.println(s));

    数组:

             //创建数组
            int[] arr = {1,2,3,4,5,6,7};
            Arrays.stream(arr).forEach(s-> System.out.println(s));

    零散数据:

    Stream.of(1,2,3,4).forEach(s-> System.out.println(s));

    注意点:

    引用数据类型数组可以Stream.of 但是基本数据类型不行

  2. 利用流中API操作

    过滤 转换 -> 中间方法 (之后可继续调用其他方法)

    统计 打印 -> 终结方法 (之后不可调用其他)

中间操作

筛选与切片

filter ->过滤

limit -> 获取前几个元素

skip -> 跳过前几个元素

distinct -> 元素去重 依赖(hashCode和equals方法)

concat -> 合并a,b两个流为一个流(父类)

filter
         ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123","b123","c222","d11","e22","f11");
         //过滤
//        list.stream().filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                //返回值为true 留下 false 舍去
//                return s.startsWith("a");
//            }
//        }).forEach(s-> System.out.println(s));
        list.stream().filter(s->s.startsWith("a")).forEach(s-> System.out.println(s));
limit/skip
        //得到前三个
        list.stream().limit(3).forEach(s-> System.out.println(s));
        //跳过前4个
        list.stream().skip(4).forEach(s-> System.out.println(s));
distinct
list.stream().distinct().forEach(s-> System.out.println(s));
concat
Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.println(s));
映射

map -> 转换流中数据类型 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

flatMap -> 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

mapToDouble -> 产生一个新的 DoubleStream

mapToInt -> 产生一个新的 IntStream

mapToLong -> 产生一个新的 LongStream。

注意:不影响原数据

map
          ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-15","b123-56","a123-22","d11-25","e22-525","f11-59");
        //只获取里面 -后数据 String ->int
        // 第一个类型:流中数据原本类型 第二个类型:要转的类型
        //apply形参s:流中数据
        //返回值 转换后数据
        //当map方法执行完毕后 流上的数据 变成了整数
//        list.stream().map(new Function<String, Integer>() {
//            @Override
//            public Integer apply(String s) {
//                String[] arr = s.split("-");
//                String ageString = arr[1];
//                int age = Integer.parseInt(ageString);
//                return age;
//            }
//        }).forEach(s-> System.out.println(s));
        list.stream().map(s-> Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));
​
​
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-男-15","b123-男-56","a123-女-22","d11-女-25","e22-女-525","f11-女-59");
        //拿到名字长度大于3的名字
        //先拿到名字
        List<String> collect = list.stream().map(e -> e.split("-")[0]).filter(s -> s.length() > 3).collect(Collectors.toList());
        List<String> collect = list.stream().map(Employee::getName).filter(s -> s.length() > 3).collect(Collectors.toList());

//假设希望筛选出所有专业为计算机科学的学生姓名,可以在filter筛选的基础之上,通过map将学生实体映射成为学生姓名字符串
List<String> names = students.stream()
                            .filter(student -> "计算机科学".equals(student.getMajor()))
                            .map(Student::getName).collect(Collectors.toList());
//希望计算所有专业为计算机科学学生的年龄之和
int totalAge = students.stream()
                    .filter(student -> "计算机科学".equals(student.getMajor()))
                    .mapToInt(Student::getAge).sum();
flatMap

flatMap是将一个流中的每个值都转成一个个流,然后再将这些流扁平化成为一个流 stream中stream

//输出构成这一数组的所有非重复字符
String[] strs = {"java8", "is", "easy", "to", "use"};
List<String[]> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                                .distinct()
                                .collect(Collectors.toList());
    /*
            [j, a, v, a, 8]
            [i, s]
            [e, a, s, y]
            [t, o]
            [u, s, e]
    */
List<String> distinctStrs = Arrays.stream(strs)
                                .map(str -> str.split(""))  // 映射成为Stream<String[]>
                                .flatMap(Arrays::stream)  // 扁平化为Stream<String>
                                .distinct()
                                .collect(Collectors.toList());
//books->list
Book book = writers.stream().flatMap(writer -> writer.getBooks().stream())
                .max(new BookComparator()).get();

并、交、差

        List<String> A = new ArrayList<>();
        Collections.addAll(A,"1","2","3","4");
        List<String> B = new ArrayList<>();
        Collections.addAll(A,"3","4","5","6","7");
​
        //并集
        A.addAll(B);
        List<String> AuB = A.stream().distinct().collect(Collectors.toList());
        System.out.println("并集:" + AuB);
        //[1, 2, 3, 4, 5, 6, 7]
​
        //交集  B::contains = s -> B.contains(s) 高版本IDEA会提示转换
        List<String> AnB = A.stream().filter(B::contains).collect(Collectors.toList());
        System.out.println("交集:" + AnB);
        //[3, 4]
​
        //差集 
        List<String> difference = A.stream().filter(s -> !B.contains(s)).collect(Collectors.toList());
        System.out.println("A中B的补集:" + difference);

排序

sorted() -> 自然排序 升序

sorted(Comparator com) -> 按比较器顺序排序

//升序
//1.自然排序
list = list.stream().sorted().collect(Collectors.toList());
//2.比较器 根据年龄排序
list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());
​
//降序
//1.自然排序  使用Comparator 提供的reverseOrder() 方法
list = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
//2.比较器 根据年龄排序
list = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
​
​
//多字段排序
//先按姓名升序,姓名相同则按年龄升序
list = list.stream().sorted(Comparator.comparing(Student::getName).thenComparing(Student::getAge)).collect(Collectors.toList());
Match 匹配

match用来做匹配操作,它的返回值是一个 boolean 类型。通过 match, 可以方便的验证一个 list 中是否存在某个类型的元素。

// 验证 list 中 string 是否有以 a 开头的, 匹配到第一个,即返回 true
boolean anyStartsWithA =
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));
​
System.out.println(anyStartsWithA);      // true
​
// 验证 list 中 string 是否都是以 a 开头的
boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));
​
System.out.println(allStartsWithA);      // false
​
// 验证 list 中 string 是否都不是以 z 开头的,
boolean noneStartsWithZ =
    stringCollection
        .stream()
        .noneMatch((s) -> s.startsWith("z"));
​
System.out.println(noneStartsWithZ);      // true

终结方法

forEach -> 遍历

(long)count -> 统计

Reduce -> 规约

toArray() -> 收集流中的数据 放到数组中

collect (Collector collector) -> 收集流中数据 放到集合

Count

count 是一个终端操作,它能够统计 stream 流中的元素总数,返回值是 long 类型

// 先对 list 中字符串开头为 b 进行过滤,让后统计数量
long startsWithB =
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();

System.out.println(startsWithB);    // 3
Reduce

Reduce 中文翻译为:减少、缩小。通过入参的 Function,能够将 list 归约成一个值。它的返回类型是 Optional 类型。

Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
BigDecimal subjectTotalIncomeBudget = entry.getValue().stream()
                           .map(PmJtProjectSaleContractPrice::getTotalAmountExcludeTax).reduce(BigDecimal.ZERO,BigDecimal::add);
//BigDecimal.ZERO: 这表示初始值。在执行 reduce 操作时,首次使用的值为初始值。在这里,BigDecimal.ZERO 表示初始值为 0。
//BigDecimal::add: 这表示一个 BinaryOperator,即表示如何将两个元素结合起来。在这里,使用了 BigDecimal 类的 add 方法,表示将两个 BigDecimal 相加。
collect
		//toArray() 
 		ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-15","b123-56","a123-22","d11-25","e22-525","f11-59");
        System.out.println(Arrays.toString(list.stream().toArray()));
//        String[] arr = list.stream().toArray(new IntFunction<String[]>() {
//            @Override
//            public String[] apply(int value) {
//                return new String[value];
//            }
//        });
        System.out.println(Arrays.toString(list.stream().toArray(value->new String[value])));

collect (Collector collector) -> 收集流中数据 放到集合中 (List Set Map)

		ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a123-男-15","b123-男-56","a123-女-22","d11-女-25","e22-女-525","f11-女-59");
        //收集男性
        list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                //.collect(Collectors.toList());收集到List集合中 不去重
                //.collect(Collectors.toSet());收集到Set中 去重
            
            
-----------------------------------------------------------
                 ArrayList<String> list = new ArrayList<>();
                 Collections.addAll(list,"a123-男-15","b123-男-56","a123-女-22","d11-女-25","e22-女-525","f11-女-59");
                //收集到map中 键值
                //注意点:键不能重复 
                //收集男性 键:姓名 值:年龄
                /*list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                 *//*  toMap: 键的规则 值的规则
                        键的规则:Function 泛型 (流中每一个数据的类型,map集合中键的类型) ->生成键 返回键
                        值的规则:Function 泛型 (流中每一个数据的类型,map集合中值的类型) ->生成值 返回值
                 *//*
                .collect(Collectors.toMap(new Function<String, String>() {
                                              @Override
                                              public String apply(String s) {
                                                  //生成键
                                                  return s.split("-")[0];
                                              }  
                                          },
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);
                            }
                        }));*/

			list.stream()  
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toMap(s->s.split("-")[0],s-> Integer.parseInt(s.split("-")[2])));

例子

//List<List<FieldAttributeDto>> tableValue 根据FieldAttributeDto中的FiledName="records_projectStage"的value的值(string)来进行排序(升序)
//flatMap      当阶段1-11时出错
List<FieldAttributeDto> flattenedSortedTableValue = tableValue.stream()
						.flatMap(List::stream)  // 将嵌套的列表扁平化为单个元素的流
						.filter(dto -> "records_projectStage".equals(dto.getFieldName()))  // 过滤出符合条件的 FieldAttributeDto
						.sorted(Comparator.comparing(FieldAttributeDto::getLabelValue))  // 对符合条件的 FieldAttributeDto 进行排序
						.collect(Collectors.toList());  // 收集结果为列表
//解决 限制 "阶段"开头
List<FieldAttributeDto> flattenedSortedTableValue = tableValue.stream()
						.flatMap(List::stream)  // 将嵌套的列表扁平化为单个元素的流
						.filter(dto -> "records_projectStage".equals(dto.getFieldName()))  // 过滤出符合条件的 FieldAttributeDto
						.sorted(Comparator.comparing(this::parseStage))
								.collect(Collectors.toList());  // 收集结果为列表
	// 自定义方法,将阶段字符串解析为整数
	private  int parseStage(FieldAttributeDto dto) {
		String stage = dto.getLabelValue();
		if (stage.startsWith("阶段")) {
			return Integer.parseInt(stage.substring(2));
		}
		return 0; // 默认值
	}

 List<List<FieldAttributeDto>> sortedTableValue = tableValue.stream()
                .map(list -> list.stream()
                        .filter(dto -> dto.getFieldName().equals("records_projectStage"))
                        .findFirst()
                        .orElse(null))
                .filter(dto -> dto != null)
                .sorted(Comparator.comparing(FieldAttributeDto::getValue))
                .map(dto -> tableValue.stream()
                        .filter(list -> list.contains(dto))
                        .findFirst()
                        .orElse(null))
                .filter(list -> list != null)
                .collect(Collectors.toList());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伏颜.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值