Java_集合之四
1.1可变参数【应用】
-
可变参数介绍
-
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
-
方法的参数类型已经确定,个数不确定,我们可以使用可变参数
-
-
可变参数定义格式
修饰符 返回值类型 方法名(数据类型… 变量名) { } -
可变参数的注意事项
-
-
如果一个方法有多个参数,包含可变参数,可变参数要放在最后
-
-
可变参数的基本使用
1 public class ArgsDemo01 { 2 public static void main(String[] args) { 3 System.out.println(sum(10, 20)); 4 System.out.println(sum(10, 20, 30)); 5 System.out.println(sum(10, 20, 30, 40)); 6 7 System.out.println(sum(10,20,30,40,50)); 8 System.out.println(sum(10,20,30,40,50,60)); 9 System.out.println(sum(10,20,30,40,50,60,70)); 10 System.out.println(sum(10,20,30,40,50,60,70,80,90,100)); 11 } 12 13 // public static int sum(int b,int... a) { 14 // return 0; 15 // } 16 17 public static int sum(int... a) { 18 int sum = 0; 19 for(int i : a) { 20 sum += i; 21 } 22 return sum; 23 } 24 }
1.2创建不可变集合【理解】
-
方法介绍
-
在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合
-
这个集合不能添加,不能删除,不能修改
-
但是可以结合集合的带参构造,实现集合的批量添加
-
-
在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
-
首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
-
-
-
示例代码
1 public class MyVariableParameter4 { 2 public static void main(String[] args) { 3 // static <E> List<E> of(E…elements) 创建一个具有指定元素的List集合对象 4 //static <E> Set<E> of(E…elements) 创建一个具有指定元素的Set集合对象 5 //static <K , V> Map<K,V> of(E…elements) 创建一个具有指定元素的Map集合对象 6 7 //method1(); 8 //method2(); 9 //method3(); 10 //method4(); 11 12 } 13 14 private static void method4() { 15 Map<String, String> map = Map.ofEntries( 16 Map.entry("zhangsan", "江苏"), 17 Map.entry("lisi", "北京")); 18 System.out.println(map); 19 } 20 21 private static void method3() { 22 Map<String, String> map = Map.of("zhangsan", "江苏", "lisi", "北京", "wangwu", "天津"); 23 System.out.println(map); 24 } 25 26 private static void method2() { 27 //传递的参数当中,不能存在重复的元素。 28 Set<String> set = Set.of("a", "b", "c", "d","a"); 29 System.out.println(set); 30 } 31 32 private static void method1() { 33 List<String> list = List.of("a", "b", "c", "d"); 34 System.out.println(list); 35 //list.add("Q"); 36 //list.remove("a"); 37 //list.set(0,"A"); 38 //System.out.println(list); 39 40 // ArrayList<String> list2 = new ArrayList<>(); 41 // list2.add("aaa"); 42 // list2.add("aaa"); 43 // list2.add("aaa"); 44 // list2.add("aaa"); 45 46 //集合的批量添加。 47 //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。 48 //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。 49 ArrayList<String> list3 = new ArrayList<>(List.of("a", "b", "c", "d")); 50 System.out.println(list3); 51 } 52 }
2.Stream流
2.1体验Stream流【理解】
-
案例需求
按照下面的要求完成集合的创建和遍历
-
创建一个集合,存储多个字符串元素
-
把集合中所有以"张"开头的元素存储到一个新的集合
-
把"张"开头的集合中的长度为3的元素存储到一个新的集合
-
遍历上一步得到的集合
-
-
原始方式示例代码
1 public class MyStream1 { 2 public static void main(String[] args) { 3 //集合的批量添加 4 ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); 5 //list.add() 6 7 //遍历list1把以张开头的元素添加到list2中。 8 ArrayList<String> list2 = new ArrayList<>(); 9 for (String s : list1) { 10 if(s.startsWith("张")){ 11 list2.add(s); 12 } 13 } 14 //遍历list2集合,把其中长度为3的元素,再添加到list3中。 15 ArrayList<String> list3 = new ArrayList<>(); 16 for (String s : list2) { 17 if(s.length() == 3){ 18 list3.add(s); 19 } 20 } 21 for (String s : list3) { 22 System.out.println(s); 23 } 24 } 25 }
-
使用Stream流示例代码
1 public class StreamDemo { 2 public static void main(String[] args) { 3 //集合的批量添加 4 ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤")); 5 6 //Stream流 7 list1.stream().filter(s->s.startsWith("张")) 8 .filter(s->s.length() == 3) 9 .forEach(s-> System.out.println(s)); 10 } 11 }
-
Stream流的好处
-
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
-
Stream流把真正的函数式编程风格引入到Java中
-
代码简洁
-
2.2Stream流的常见生成方式【应用】
-
Stream流的思想

-
Stream流的三类方法
-
获取Stream流
-
创建一条流水线,并把数据放到流水线上准备进行操作
-
-
中间方法
-
流水线上的操作
-
一次操作完毕之后,还可以继续进行其他操作
-
-
终结方法
-
一个Stream流只能有一个终结方法
-
是流水线上的最后一个操作
-
-
-
生成Stream流的方式
-
Collection体系集合
使用默认方法stream()生成流, default Stream<E> stream()
-
Map体系集合
把Map转成Set集合,间接的生成流
-
数组
通过Arrays中的静态方法stream生成流
-
同种数据类型的多个数据
通过Stream接口的静态方法of(T... values)生成流
-
-
代码演示
1 public class StreamDemo { 2 public static void main(String[] args) { 3 //Collection体系的集合可以使用默认方法stream()生成流 4 List<String> list = new ArrayList<String>(); 5 Stream<String> listStream = list.stream(); 6 7 Set<String> set = new HashSet<String>(); 8 Stream<String> setStream = set.stream(); 9 10 //Map体系的集合间接的生成流 11 Map<String,Integer> map = new HashMap<String, Integer>(); 12 Stream<String> keyStream = map.keySet().stream(); 13 Stream<Integer> valueStream = map.values().stream(); 14 Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream(); 15 16 //数组可以通过Arrays中的静态方法stream生成流 17 String[] strArray = {"hello","world","java"}; 18 Stream<String> strArrayStream = Arrays.stream(strArray); 19 20 //同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流 21 Stream<String> strArrayStream2 = Stream.of("hello", "world", "java"); 22 Stream<Integer> intStream = Stream.of(10, 20, 30); 23 } 24 }
2.3Stream流中间操作方法【应用】
-
概念
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
-
常见方法
方法名 说明 Stream<T> filter(Predicate predicate) 用于对流中的数据进行过滤 Stream<T> limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据 Stream<T> skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 static <T> Stream<T> concat(Stream a, Stream b) 合并a和b两个流为一个流 Stream<T> distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流 -
filter代码演示
1 public class MyStream3 { 2 public static void main(String[] args) { 3 // Stream<T> filter(Predicate predicate):过滤 4 // Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值 5 6 ArrayList<String> list = new ArrayList<>(); 7 list.add("张三丰"); 8 list.add("张无忌"); 9 list.add("张翠山"); 10 list.add("王二麻子"); 11 list.add("张良"); 12 list.add("谢广坤"); 13 14 //filter方法获取流中的 每一个数据. 15 //而test方法中的s,就依次表示流中的每一个数据. 16 //我们只要在test方法中对s进行判断就可以了. 17 //如果判断的结果为true,则当前的数据留下 18 //如果判断的结果为false,则当前数据就不要. 19 // list.stream().filter( 20 // new Predicate<String>() { 21 // @Override 22 // public boolean test(String s) { 23 // boolean result = s.startsWith("张"); 24 // return result; 25 // } 26 // } 27 // ).forEach(s-> System.out.println(s)); 28 29 //因为Predicate接口中只有一个抽象方法test 30 //所以我们可以使用lambda表达式来简化 31 // list.stream().filter( 32 // (String s)->{ 33 // boolean result = s.startsWith("张"); 34 // return result; 35 // } 36 // ).forEach(s-> System.out.println(s)); 37 38 list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s)); 39 40 } 41 }
-
limit&skip代码演示
1 public class StreamDemo02 { 2 public static void main(String[] args) { 3 //创建一个集合,存储多个字符串元素 4 ArrayList<String> list = new ArrayList<String>(); 5 6 list.add("林青霞"); 7 list.add("张曼玉"); 8 list.add("王祖贤"); 9 list.add("柳岩"); 10 list.add("张敏"); 11 list.add("张无忌"); 12 13 //需求1:取前3个数据在控制台输出 14 list.stream().limit(3).forEach(s-> System.out.println(s)); 15 System.out.println("--------"); 16 17 //需求2:跳过3个元素,把剩下的元素在控制台输出 18 list.stream().skip(3).forEach(s-> System.out.println(s)); 19 System.out.println("--------"); 20 21 //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出 22 list.stream().skip(2).limit(2).forEach(s-> System.out.println(s)); 23 } 24 }
-
concat&distinct代码演示
1 public class StreamDemo03 { 2 public static void main(String[] args) { 3 //创建一个集合,存储多个字符串元素 4 ArrayList<String> list = new ArrayList<String>(); 5 6 list.add("林青霞"); 7 list.add("张曼玉"); 8 list.add("王祖贤"); 9 list.add("柳岩"); 10 list.add("张敏"); 11 list.add("张无忌"); 12 13 //需求1:取前4个数据组成一个流 14 Stream<String> s1 = list.stream().limit(4); 15 16 //需求2:跳过2个数据组成一个流 17 Stream<String> s2 = list.stream().skip(2); 18 19 //需求3:合并需求1和需求2得到的流,并把结果在控制台输出 20 // Stream.concat(s1,s2).forEach(s-> System.out.println(s)); 21 22 //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复 23 Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s)); 24 } 25 }
2.4Stream流终结操作方法【应用】
-
概念
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
-
常见方法
方法名 说明 void forEach(Consumer action) 对此流的每个元素执行操作 long count() 返回此流中的元素数 -
代码演示
1 public class MyStream5 { 2 public static void main(String[] args) { 3 ArrayList<String> list = new ArrayList<>(); 4 list.add("张三丰"); 5 list.add("张无忌"); 6 list.add("张翠山"); 7 list.add("王二麻子"); 8 list.add("张良"); 9 list.add("谢广坤"); 10 11 //method1(list); 12 13 // long count():返回此流中的元素数 14 long count = list.stream().count(); 15 System.out.println(count); 16 } 17 18 private static void method1(ArrayList<String> list) { 19 // void forEach(Consumer action):对此流的每个元素执行操作 20 // Consumer接口中的方法void accept(T t):对给定的参数执行此操作 21 //在forEach方法的底层,会循环获取到流中的每一个数据. 22 //并循环调用accept方法,并把每一个数据传递给accept方法 23 //s就依次表示了流中的每一个数据. 24 //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了. 25 list.stream().forEach( 26 new Consumer<String>() { 27 @Override 28 public void accept(String s) { 29 System.out.println(s); 30 } 31 } 32 ); 33 34 System.out.println("===================="); 35 //lambda表达式的简化格式 36 //是因为Consumer接口中,只有一个accept方法 37 list.stream().forEach( 38 (String s)->{ 39 System.out.println(s); 40 } 41 ); 42 System.out.println("===================="); 43 //lambda表达式还是可以进一步简化的. 44 list.stream().forEach(s->System.out.println(s)); 45 } 46 }
2.5Stream流的收集操作【应用】
-
概念
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
-
常用方法
方法名 说明 R collect(Collector collector) 把结果收集到集合中 -
工具类Collectors提供了具体的收集方式
方法名 说明 public static <T> Collector toList() 把元素收集到List集合中 public static <T> Collector toSet() 把元素收集到Set集合中 public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中 -
代码演示
1 // toList和toSet方法演示 2 public class MyStream7 { 3 public static void main(String[] args) { 4 ArrayList<Integer> list1 = new ArrayList<>(); 5 for (int i = 1; i <= 10; i++) { 6 list1.add(i); 7 } 8 9 list1.add(10); 10 list1.add(10); 11 list1.add(10); 12 list1.add(10); 13 list1.add(10); 14 15 //filter负责过滤数据的. 16 //collect负责收集数据. 17 //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中. 18 //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中. 19 List<Integer> list = list1.stream().filter(number -> number % 2 == 0) 20 .collect(Collectors.toList()); 21 22 System.out.println(list); 23 24 Set<Integer> set = list1.stream().filter(number -> number % 2 == 0) 25 .collect(Collectors.toSet()); 26 System.out.println(set); 27 } 28 } 29 /** 30 Stream流的收集方法 toMap方法演示 31 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄 32 "zhangsan,23" 33 "lisi,24" 34 "wangwu,25" 35 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值 36 */ 37 public class MyStream8 { 38 public static void main(String[] args) { 39 ArrayList<String> list = new ArrayList<>(); 40 list.add("zhangsan,23"); 41 list.add("lisi,24"); 42 list.add("wangwu,25"); 43 44 Map<String, Integer> map = list.stream().filter( 45 s -> { 46 String[] split = s.split(","); 47 int age = Integer.parseInt(split[1]); 48 return age >= 24; 49 } 50 51 // collect方法只能获取到流中剩余的每一个数据. 52 //在底层不能创建容器,也不能把数据添加到容器当中 53 54 //Collectors.toMap 创建一个map集合并将数据添加到集合当中 55 56 // s 依次表示流中的每一个数据 57 58 //第一个lambda表达式就是如何获取到Map中的键 59 //第二个lambda表达式就是如何获取Map中的值 60 ).collect(Collectors.toMap( 61 s -> s.split(",")[0], 62 s -> Integer.parseInt(s.split(",")[1]) )); 63 64 System.out.println(map); 65 } 66 }
5.6Stream流综合练习【应用】
-
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
-
男演员只要名字为3个字的前三人
-
女演员只要姓林的,并且不要第一个
-
把过滤后的男演员姓名和女演员姓名合并到一起
-
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
-
-
代码实现
演员类
1 public class Actor { 2 private String name; 3 4 public Actor(String name) { 5 this.name = name; 6 } 7 8 public String getName() { 9 return name; 10 } 11 12 public void setName(String name) { 13 this.name = name; 14 } 15 }
测试类
1 public class StreamTest { 2 public static void main(String[] args) { 3 //创建集合 4 ArrayList<String> manList = new ArrayList<String>(); 5 manList.add("周润发"); 6 manList.add("成龙"); 7 manList.add("刘德华"); 8 manList.add("吴京"); 9 manList.add("周星驰"); 10 manList.add("李连杰"); 11 12 ArrayList<String> womanList = new ArrayList<String>(); 13 womanList.add("林心如"); 14 womanList.add("张曼玉"); 15 womanList.add("林青霞"); 16 womanList.add("柳岩"); 17 womanList.add("林志玲"); 18 womanList.add("王祖贤"); 19 20 //男演员只要名字为3个字的前三人 21 Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3); 22 23 //女演员只要姓林的,并且不要第一个 24 Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1); 25 26 //把过滤后的男演员姓名和女演员姓名合并到一起 27 Stream<String> stream = Stream.concat(manStream, womanStream); 28 29 // 将流中的数据封装成Actor对象之后打印 30 stream.forEach(name -> { 31 Actor actor = new Actor(name); 32 System.out.println(actor); 33 }); 34 } 35 }
-

浙公网安备 33010602011771号