不可变集合 Stream流

不可变集合



如果牌盒里的牌固定为那54张,不能被改变

  • 如出牌规则不可变
  • 通过of方法获取不可变集合

    不可变集合是java9提出的新特性
    在List Map Set中都定义了许多重载的静态of方法,用于获取指定内容的不可变的集合,如下面是List中定义的of方法

这些方法将直接返回List Map Set的集合,就相当于已经通过多态得到了List Map Set这写接口的对象,但是在调用时也只能调用在子类中覆写自接口的抽象方法
java提供了指定任意个集合内容的of方法,因为不支持添加操作,所有这样设置

List的不可变集合演示

//演示List的不可变集合


import java.util.*;
public class Main{
    public static void main(String[]args){
        /*
        不可变集合特点:
        一旦集合被创建 其集合的内容只能支持查询操作
        不能进行添加(增)删除 修改*/
        
        //1.创建List不可变集合
      List<String> list= List.of("张三","李四","王五","赵六");//添加3个对象
      //2.查询每一个成员:通过索引得到每一个元素
      System.out.println(list.get(0));
      System.out.println(list.get(1));
      System.out.println(list.get(2));
      System.out.println(list.get(3));
      System.out.println("-----------------------------------------------------");
      //3.遍历集合
      //3.1用迭代器遍历
      Iterator<String> it =list.iterator();//获取迭代器对象
      while(it.hasNext()){
          String a = it.next();//获取元素并向后移动指针
          System.out.println(a);
      }
      System.out.println("-------------------------------------------------");
      //4.用增强for遍历集合
      for(String c:list){
          System.out.println(c);
      }
      //5.测试不能进行增删改
      //5.1增
    //  list.add("hello");//向集合中添加:将会抛出异常
    //5.2删
    //list.remove("张三");//删除集合中的指定元素:将会抛出异常
    //5.3修改
    //list.set(0,"hello");//将指定索引处的元素修改成指定的元素:将会抛出异常
      
    }
}

Set集合的可变集合(和List类似)

//演示Set的不可变集合
import java.util.*;
public class Main{
    public static void main(String[]args){
        /*
        不可变集合特点:
        一旦集合被创建 其集合的内容只能支持查询操作
        不能进行添加(增)删除 修改*/
        
        //1.创建Set不可变集合
    Set<String> set= Set.of("张三","李四","王五","赵六");//添加3个对象
      
      //3.遍历集合
      //3.1用迭代器遍历
      Iterator<String> it =set.iterator();//获取迭代器对象
      while(it.hasNext()){
          String a = it.next();//获取元素并向后移动指针
          System.out.println(a);
      }
      System.out.println("-------------------------------------------------");
      //4.用增强for遍历集合
      for(String c:set){
          System.out.println(c);
      }
     //测试不能进行增删该操作
     //1.增
     //set.add("hello");//将会抛出异常
     //2.删
    // set.remove("张三");//将会抛出异常
    //3.改:Set中没有修改操作
    set.clear();//清空也会报错
    
     
      
    }
}

Set不可变集合的细节:当我们要获取一个不可变的Set集合时,of方法里面的参数(即不可变集合的内容一定要保证其唯一性)
Map集合的不可变集合

Map不可变集合的细节:1.of方法的参数(即集合的内容)不能重复 2.在Map中的of方法没有带有可变参数的of方法,Map集合的of方法最多只能传递20个参数,即只能传递10对键值对

对于Map集合的of方法,可以用来创建0-10对键值对的不可变的Map集合,捕捉和Set和List类似,这里不再演示

为什么Map集合没有设置可变参数

Map集合是双列集合和前面的单列集合不一样,它的每个成员是由2个对象构成,当我们的of方法得需要可以添加任意个的成员,而一个键对应一个值,这说明键需要可以添加任意个,值也可以添加任意个,则需要将of方法设置成以下的样式

public static  <K,V> Map<K,V> of(K... k1,V... v1){

        }

但是这违反了可变参数的规定,即函数的可变参数只能有一个并且放在最后

如果我们需要创建的键值对对象超过10该怎么办?

public static <K,​V> Map<K,​V> ofEntries​(Map.Entry<? extends K,​? extends V>... entries)

Map集合的ofEntries方法可以返回Map的不可变集合,主要是任意个参数都可以

此时的改进思想是将键和值包装成一个集合,这样就只用写一个参数即可,ofEntries函数就是利用了这一点

public static <K,​V> Map<K,​V> copyOf​(Map<? extends K,​? extends V> map)(jdk10新特性)
该方法的参数直接用Map即可(或者是其子类)
可以使用可变参数传递任意参数演示

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        //测试Map的不可变参数(特指可以创建任意个成员变量的函数)
        //1.ofEntries函数 static<K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>...entries)
        //该方法的参数是Entry集合
        HashMap<String,String> hm = new HashMap<>();//创建一个map集合
        //在hm集合中添加任意个参数
        hm.put("张三","北京");
        hm.put("李四","南京");
        hm.put("王五","武汉");
        hm.put("赵六","天津");
        hm.put("郝建","上海");
         Set<Map.Entry<String, String>> entries = hm.entrySet();
         //方法一
         //2.将entries变成一个数组
        Map.Entry[]arr1 = new Map.Entry[0];//创建数组用于储存集合里的内容(这里直接写0底层会重新创建数组)
        Map.Entry[]arr2 = entries.toArray(arr1);//现在arr2里面储存的就是所有的Entry对象
        /*
        toArray函数的细节(将集合变成数组):
        toArray函数在底层会比较集合的长度和数组(用来装集合的数组)长度的大小
        *如果集合长度>数组长度:数据在数组中放不下,此时会根据实际数据的长度,重新创建数组
        *如果集合长度<=数组长度:数据在数组中放的下,此时不会创建新的数组,而是直接使用
        所有用来存放数据的数组长度直接写0即可
         */
       Map<String,String> map= Map.ofEntries(arr2);
       //ofEntries的参数是Entry集合的可变集合,在传参的时候可以传递任意个Entry集合,由于可变参数的底层是一个数组,所有
        //我们在传递参数是时候也可以传递一个对象数组(对象为Entry类型)
       //2.上面写的有点复杂,我们利用链式编程简化代码
       //方法一(优化版)
       Map<String,String> map1= Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
  
      //用copyOf(方法二)
      Map<String,String> map2=Map.copyOf(hm);//该方法返回Map的不可变集合
      System.out.println(map2);
    }
}

Stream流

体验Stream流的作用

package com.an.a;

import java.util.ArrayList;

//测试Stream流的使用
public class StreamTest {
    public static void main(String[] args) {
        /*
            创建集合添加元素,完成以下需求:
            1.把所用张开头的元素储存到新的集合中
            2.把所有张开头的,长度为3的元素再储存到新的集合中
            3.遍历打印结果
         */
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("张无忌");
        list1.add("赵敏");
        list1.add("周芷若");
        list1.add("张强");
        list1.add("张三丰");

        //1.把所有张开头的元素添加到新的集合中
        //2.把所有的张开头的并且长度为3的元素再次储存到新的集合中(这里也可以分开遍历,只需要遍历list1即可)
        ArrayList<String> list2 = new ArrayList<>();
        ArrayList<String> list3 = new ArrayList<>();
        for (String name : list1) {
            if(name.startsWith("张")){
                list2.add(name);
                if(name.length()==3){
                    list3.add(name);
                }
            }

        }
      //我们可以发现上面的代码太长了,而利用Stream流可以让代码跟简介(结合Lamdba表达式)
        list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
        //上面的代码直接可以实现对张开头并且长度为3的过滤
    }
}

Stream流的思想和获取Stream流

可以将流想象成工厂的流水线


当检查瓶子不合格就和被扔掉,符合规定将进行下面的步骤

流的思想和上面工厂相似,将数据一步步过滤,然后留下我们需要的数据

好像Lamdba表达式是基础,故先学习



注意点:1.双列集合不能直接使用Stream流进行操作,需要使用KeySet或entrySet转化成单列集合2.对于对零散数据的操作要求这些数据的类型相同
1.获取单列集合的Stream

package com.an.a;

import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;

//测试各种数据获取Stream
public class StreamTest1 {
    /*
        单列集合 default Stream<E> stream()    Collection中的默认方法
        双列集合 无                           无法直接获取Stream流
        数组    public static <T> Stream(T[]arry) Arrays类中的静态方法
        一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
     */
    public static void main(String[] args) {
        //1.单列集合获取Stream
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc","ddd");//批量添加数据
        //获取Stream:获取到一条流水线并把数据放到上面
        //遍历数据
        //Stream<String> stream = list.stream();
        //stream.forEach( s-> System.out.println(s));
        //链式编程简化代码
        list.stream().forEach(s-> System.out.println(s));
        
    }
}

对于单列集合的Set系列,和上面操作一样不再演示
2.获取双列集合的Stream

package com.an.a;

import java.util.*;
import java.util.stream.Stream;

//测试各种数据获取Stream
public class StreamTest1 {
    /*
        单列集合 default Stream<E> stream()    Collection中的默认方法
        双列集合 无                           无法直接获取Stream流
        数组    public static <T> Stream(T[]arry) Arrays类中的静态方法
        一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
     */
    public static void main(String[] args) {
      //2.获取双列集合的Stream
        HashMap<String,Integer>hm = new HashMap<>();
       hm.put("aaa",111);
       hm.put("bbb",222);
       hm.put("ccc",333);
       hm.put("ddd",444);
       //Map集合不能直接获取Stream要将其转化为Set集合
        //1.第一种方式:将所有键转化为Set
      // Set<String> keys = hm.keySet();//将所有的键转化为Set集合
        //keys.stream().forEach( s-> System.out.println(s));
        //链式编程简化
        hm.keySet().stream().forEach(s-> System.out.println(s));
        //2.第二种方法:将所有的键值对转化为Set
         Set<Map.Entry<String, Integer>> entries = hm.entrySet();
         entries.stream().forEach(s-> System.out.println(s));
         //链式编程简化
        hm.entrySet().stream().forEach(s-> System.out.println(s));

    }
}

3.获取数组的Stream

package com.an.a;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

//测试各种数据获取Stream
public class StreamTest1 {
    /*
        单列集合 default Stream<E> stream()    Collection中的默认方法
        双列集合 无                           无法直接获取Stream流
        数组    public static <T> Stream(T[]arry) Arrays类中的静态方法
        一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
     */
    public static void main(String[] args) {
     //3.获取数组的Stream
        int arr[]={1,2,4,5,6,8,0};
       String[]str={"aaa","bbb","ddd","www"};
        //获取流水线并把数组放上去

        Arrays.stream(arr).forEach(s-> System.out.println(s));
        //Arrays类的Stream方法有很多重载,以至于可以获取任意类型数组的流水线
        final Stream<String> stream = Arrays.stream(str);//引用类型的流水线
        stream.forEach(s-> System.out.println(s));


    }
}

4.获取零散数据的Stream

package com.an.a;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

//测试各种数据获取Stream
public class StreamTest1 {
    /*
        单列集合 default Stream<E> stream()    Collection中的默认方法
        双列集合 无                           无法直接获取Stream流
        数组    public static <T> Stream(T[]arry) Arrays类中的静态方法
        一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
     */
    public static void main(String[] args) {
     //获取一堆零散数据的Stream
        //这些零散数据可以是任意类型但是要求这些数据的类型相同
         Stream.of(2, 3, 4, 5, 6).forEach(s-> System.out.println(s));
         Stream.of("aaa","bbb","ccc").forEach(s-> System.out.println(s));

    }
}

关于上面of方法的小细节

package com.an.a;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

//测试各种数据获取Stream
public class StreamTest1 {
    /*
        单列集合 default Stream<E> stream()    Collection中的默认方法
        双列集合 无                           无法直接获取Stream流
        数组    public static <T> Stream(T[]arry) Arrays类中的静态方法
        一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
     */
    public static void main(String[] args) {
        //3.获取数组的Stream
        int arr[]={1,2,4,5,6,8,0};
        String[]str={"aaa","bbb","ddd","www"};
        //获取流水线并把数组放上去

        Arrays.stream(arr).forEach(s-> System.out.println(s));
        System.out.println("==========================================");
        //Arrays类的Stream方法有很多重载,以至于可以获取任意类型数组的流水线
        final Stream<String> stream = Arrays.stream(str);//引用类型的流水线
        stream.forEach(s-> System.out.println(s));
        System.out.println("==========of方法的小细节=========================");
        //Stream里面的of方法我们用来获取零散数据的Stream
        //但是我们知道of的可变参数底层是一个数组,所有也可以给它传递一个数组
        //那是不是说这种方法也可以获取数组的Stream
      Stream.of(1,2,4,5,6,8,0).forEach(s-> System.out.println(s));
      Stream.of(arr).forEach(s-> System.out.println(s));//[I@448139f0
        Stream.of(str).forEach(s-> System.out.println(s));//可以操作
        //结论:如果该数组是基本数据类型,java不能对其整体自动装箱,而是将数组整体当做一个元素放到Stream中
        //所有基本数据类型的数组将会得到其地址



    }
}

Stream是一个类,可以理解为流水线(有容器的性质,可以将元素放在里面)

Stream流的中间方法

合并流,如果2个流的数据类型不一致,那么大流的类型就是2个流的公共父类

前3个方法

package com.an.a;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

//测试Stream流的中间方法
public class TestA {
    public static void main(String[] args) {
      /*
      Stream<T>  filter(Predicate<?super T>predicate)     过滤
        limit      获取前几个元素 :Stream<T>
        skip       跳过前几个元素 :Stream<T>
        注意点:1.中间方法返回新的Stream流,原来的Stream流只能使用一次,建议用链式编程
                2.修改原来Stream流中的数据不会影响原来数组或集合中的数据
       */
        ArrayList<String> list=new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","周强","张三丰","张三","张良","王二麻子");
        //1.filter 过滤 把张开头的留下 其余数据不要
        //filter的参数是函数式接口,可以传递是匿名内部类
        /*list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {//s表示流中的每一个数据
                //如果返回值是true,表示当前数据留下
                //如果返回值是false,表示当前数据舍弃不要
                return s.startsWith("张");//startwith开头有张则返回true 否则返回false
            }
        }).forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s );
            }
        });*/
        //改写成Lambda
        //list.stream().filter( s-> s.startsWith("张")).forEach( s-> System.out.println(s ));
        //对以上注意点的验证1.原来的Stream流只能使用一次:
       // final Stream<String> stream1 = list.stream();
       // stream1.forEach(s-> System.out.println(s));//使用stream1对数据进行操作
       // stream1.count();//第二次使用stream1进行操作:IllegalStateException(将会出现异常)
        //2.操作stream原来数组或集合中的数据不变
       //list.forEach(s-> System.out.println(s));
        //2. limit      获取前几个元素:参数为前几个元素的个数(返回含有前几个元素的流)
      //  list.stream().limit(3).forEach(s-> System.out.print(s+" "));//张无忌 周芷若 赵敏
        //3. skip       跳过前几个元素 :Stream<T>(返回跳过了前几个元素的流)
      //  list.stream().skip(3).forEach(s-> System.out.print(s+" "));//张无忌 周芷若 赵敏 周强 张三丰 张三 张良 王二麻子

        //课堂练习:用limit和skip获取周强 张三丰 张三
        //思路1:前跳过前3个再获取前3个
       // list.stream().skip(3).limit(3).forEach(s-> System.out.print(s+" "));//周强 张三丰 张三 
        //思路2:前获取前6个再跳过前3个
        list.stream().limit(6).skip(3).forEach(s-> System.out.print(s+" "));//周强 张三丰 张三 



    }

}



distinct方法用于去重,再其方法的底层是通过HashSet进行去重,而HashSet是通过equals和hashCode进行去重,所以用该方法一定要重写equals和hashCode方法,如果是java定义的类,已经帮我们重写了这2个方法,如果是我们自己定义的类则一定要重写这2个方法

package com.an.a;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

//测试Stream流的中间方法
public class TestA {
    public static void main(String[] args) {
    /*
        distnct   元素去重(依赖hasCode和equals方法):
     static<T> Strean<T>   concat(Stream a,Stream b)    合并a和b两个流为一个流
     */
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌","张无忌","胡歌","张无忌","周伯通","任我行");
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"周芷若","小舞");
        //1.元素去重 distnct (依赖equals和hasCode方法)
        list1.stream().distinct().forEach(s-> System.out.print(s+" "));//张无忌 胡歌 周伯通 任我行
        //因为我们的数据类型是String,java在String在已经重写了equals和hasCode,如果数据的类型是我们自己定义的类,则我们需要在类中重写这2个方法
        //2.concat 将2个流合并成一个流
        Stream<String> stream12 = Stream.concat(list1.stream(), list2.stream());//返回一个新的流
        stream12.forEach(s-> System.out.print(s+" "));//张无忌 胡歌 周伯通 任我行 张无忌 张无忌 胡歌 张无忌 周伯通 任我行 周芷若 小舞
        //如果合并的2个流的数据类型不同,则新的流的数据类型为这2个流的公共父类,这样就不能调用子类特有的方法

    }

}



package com.an.a;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

//测试Stream流的中间方法
public class TestA {
    public static void main(String[] args) {
   /*
        map     转换流中的数据类型
    */
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌-13","赵敏-34","萧峰-23","张三丰-34","郝建-23");
        //需求:只获取里面的年龄并进行打印
        //思路:String->int
        /*
        map可以转换流中的数据类型
       map的参数是函数式接口
       第一个类型:流中原本的数据类型
       第二个类型:转换之后的数据类型
       apply方法:形参表示流中每一个数据
       返回值:表示转换之后的数据(流中数据的转换需要我们自己在该方法中实现)
         */
        //在数据处理中我们可以先获取到年龄然后进行数据转型
        //所以在下面的forEach方法中s依次表示的数据就是整数了
        list.stream().map(new Function<String, Integer>() {//要就第二个类型改成目标类型
            @Override
            public Integer apply(String s) {//s表示流中的每一个数据
              //  final String[] str = s.split("-");//按照-进行截取数据 并将截取后的数据放进数组
                //str[0]为姓名 str[1]为年龄
                //将年龄转为int

                //return Integer.parseInt(str[1]);
                //简化前面2个为一步
             return  Integer.parseInt( s.split("-")[1]);//split返回一个数组,在前面加上下标直接变成对应的字符串
            }
        }).forEach(s-> System.out.print(s+" "));//13 34 23 34 23
        //用Lambda进行简化处理
        list.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.print(s+" "));

    }

}



Stream流终结方法


toArray方法有重载,空参的toArray只能返回Object类型的数组,而有参的toArray可以自己设置返回的类型

package com.an.a;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;

//测试Stream流的终结方法
public class TestA {
    public static void main(String[] args) {
   /*
        void forEach(Consumer action)  遍历
        long count()  统计流中数据个数
        toArray() 收集流中的数据放到数组中
    */
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张三丰","张无忌","杨过","郭靖","黄蓉");
        //1.forEach遍历
        /*
        Consumer的泛型:表示流中数据的类型
        //accept方法的形参s:依次表示流中的每一个数据
        //方法体:对每一个数据的处理操作
         */
     /*   list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.print(s+" ");//张三丰 张无忌 杨过 郭靖 黄蓉
            }
        });*/
        //用Lambda改写
        list.stream().forEach(s-> System.out.print(s+" "));//张三丰 张无忌 杨过 郭靖 黄蓉
        //2.count 统计流中数据的个数
        long count = list.stream().count();
        System.out.println(count);//5
        //3.toArray 收集流中的数据并放在数组中
        //3.1返回Object类型的数组
       Object[] array = list.stream().toArray();
        System.out.println(Arrays.toString(array));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]
        //3.2返回自己设置类型的数组
        //其参数是函数式接口
        /*
        IntFunction的泛型:具体类型的数组(需要得到的数组类型)
        apply的形参:流中数据的个数,要和数组的长度保持一致
        apply的返回值:具体类型的数组
        方法体:就是创建数组
         */
        /*
        toArray方法参数的作用:负责创建一个指定类型的数组
        toArray方法底层:会依次得到流中的每一个数据并把数据放到数组当中
        toArrray的返回值是一个装着流中所有数据的数组
         */
       String[]arr= list.stream().toArray(new IntFunction<String[]>() {//将泛型该处具体类型的数组
            @Override
            public String[] apply(int value) {//返回类型改成具体类型的数组
                return new String[value];//数组长度和流中数组的个数一致
            }
        });
        System.out.println(Arrays.toString(arr));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]
        //将其改成Lambda
        String[] array1 = list.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(array1));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]

    }

}



收集方法collect

package com.an.a;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//测试Stream流的终结方法
public class TestA {
    public static void main(String[] args) {
     //collect(Collector<? super T,A,R> collector)      收集流中的数据,放到集合中(List Set Map)
        //1.收集到List集合中:要求:把所有的男性都收集起来
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌-男-12","杨过-男-24","小龙女-女-21","张三丰-男-123","黄月英-女-24");
        //当前的collect方法的参数不是函数式接口而是一个普通的接口
        //可以理解为collect方法可以返回各种类型的集合
       List<String> list1 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());
        System.out.println(list1);//[张无忌-男-12, 杨过-男-24, 张三丰-男-123]
        //2.收集到Set集合中:要求:把男性都收集起来
         Set<String> set = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
        System.out.println(set);//[杨过-男-24, 张三丰-男-123, 张无忌-男-12]
        //set和List总结:收集到Set集合中可以进行去重
        //3.收集到Map集合中
        /*
        把所有的男姓都收集起来
        键:姓名  值 :年龄
         */
        /*toMap:参数一表示键的生成规则
                参数二表示值的生成规则
        *toMap的2个参数都是函数式接口'
        *参数一:
        *       Function泛型一:表示流里面每一个数据
        *               泛型二:表示Map集合中键的数据类型
        *            方法apply形参:表示流中每一个 数据
                      方法体:生成键的代码
                      返回值:已经生成的键
        *
        *参数一:
                Function泛型一:表示流中每一个数据
                         泛型二:表示Map集合中值的数据类型
                 方法apply形参:依次表示流中每一个数据
                               方法体:生成值的代码
                               返回值:已经生成的值
        *
        *
        *
         */
        //张无忌-男-12
       /* Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1])).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]);
            }
        }));
        System.out.println(map);//{杨过=24, 张三丰=123, 张无忌=12}*/
        //细节:收集到Map集合中键不能重复(和Map集合的性质有关)
        //将其用Lambda进行简化
        Map<String, Integer> map = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toMap( s-> s
                        .split("-")[0],  s-> Integer.parseInt(s.split("-")[2])));
        System.out.println(map);
    }

}



Stream的综合练习

综合练习1--数字过滤

package com.an.a;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

//关于Stream的综合练习
public class StreamTestB {
    public static void main(String[] args) {
        /*
            定义一个集合,并添加一些整数 1,2,3,4,5,6,7,8,9,10
            过滤奇数,之留下偶数
            并将集合保存起来
         */
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
        //抽象方法的形参为数据 该数据保留返回true 该数据去除返回false
        List<Integer> list1 = list.stream().filter(s -> s % 2 == 0).collect(Collectors.toList());//[2, 4, 6, 8, 10]
        System.out.println(list1);
    }
}

package com.an.a;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

//关于Stream的综合练习
public class StreamTestB {
    public static void main(String[] args) {
      /*
      创建一个ArrayList集合,并添加以下字符串,字符串前面是姓名,后面是年龄
      张三,23   lisi,24  wangwu,25
      保留年龄大于等于24岁的人,并收集到Map集合中 姓名为键 年龄为值
       */
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list," 张三,23","lisi,24","wangwu,25");
     /*   Map<String, Integer> map = list.stream()
                .filter(s -> Integer.parseInt(s
                        .split(",")[1]) >= 24).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(",")[1]);
                    }
                }));*/
        //Lambda进行简写
       Map<String, Integer> map = list.stream().filter(s -> Integer
                        .parseInt(s.split(",")[1]) >= 24)
                .collect(Collectors.toMap(s -> s.split(",")[0],
                        s -> Integer.parseInt(s.split(",")[1])));
        System.out.println(map);//{lisi=24, wangwu=25}



    }
}

idea快捷键 ctrl+Alt+L格式化代码

  • Actor类
package com.an.a;

public class Actor {
    private String name;
    private int age;

    public Actor() {
    }

    public Actor(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Actor{name = " + name + ", age = " + age + "}";
    }
}

  • 程序主体
package com.an.a;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//关于Stream的综合练习
public class StreamTestB {
    public static void main(String[] args) {
     /*
     现在有2个ArrayList集合,分别储存6个男演员的姓名年龄和6名女演员的姓名年龄
     姓名和年龄用逗号隔开
     要求完成如下操作:
     比如  张三,23(依次进行以下步骤)
     1.男演员只要为3个字的前2个人
     2.女演员只要姓杨的,并且不要第一个
     3.把过滤后的男演员和女演员的姓名合并在一起
     4.将上一步的演员姓名封装成Actor对象
     5,将所有的演员对象都保存在List集合中
     男演员:蔡坤坤,24  叶天天,23  刘不甜,22  吴签,24  谷嘉,30 萧凉凉,27
     女演员:赵小颖,35  杨颖,36   高圆圆,43   张天天,31 刘诗,35 杨小幂,33
     Actor类属性只有 姓名 年龄
      */
        //创建2个ArrayList集合分别分别储存男女演员信息
        ArrayList<String> manList = new ArrayList<>();
        Collections.addAll(manList,"蔡坤坤,24","叶天天,23","刘不甜,22","吴签,24","谷嘉,30","萧凉凉,27");
        ArrayList<String> womenList = new ArrayList<>();
        Collections.addAll(womenList,"赵小颖,35","杨颖,36","高圆圆,43","张天天,31","刘诗,35","杨小幂,33");
       // 1.男演员只要为3个字的前2个人.
        Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);
        // 2.女演员只要姓杨的,并且不要第一个
       Stream<String> stream2 = womenList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);
        // 3.把过滤后的男演员和女演员的姓名合并在一起
        //4.将上一步的演员姓名封装成Actor对象 (将流中的数据进行数据转换)
        //Stream-->Actor
        //Function 第一个参数 原数据类型
        //          第二个参数 目标类型
        /*
        apply s表示每一个数据
        返回 目标数据
         */
        /*Stream.concat(stream1,stream2).map(new Function<String, Actor>() {
            @Override
            public Actor apply(String s) {//蔡坤坤,24
                String name = s.split(",")[0];//姓名
               int age = Integer.parseInt(s.split(",")[1]);//年龄
                return new Actor(name,age);
            }
        });*/
        //修改为Lambda
       Stream.concat(stream1,stream2)
                .map(s->new Actor(s.
                        split(",")[0],(Integer.parseInt(s.split(",")[1]))));


//经验教训:Stream流只能被使用一次



    }
}

posted @ 2023-01-09 18:53  一往而深,  阅读(54)  评论(0编辑  收藏  举报