JAVA Stream流
体验Stream流
Stream流的好处:
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
Stream流把真正的函数式编程风格引入到Java中
1 /*案例需求 2 按照下面的要求完成集合的创建和遍历 3 创建一个集合,存储多个字符串元素 4 把集合中所有以"张"开头的元素存储到一个新的集合 5 把"张"开头的集合中的长度为3的元素存储到一个新的集合 6 遍历上一步得到的集合*/ 7 8 import java.util.ArrayList; 9 10 public class StreamDemo { 11 public static void main(String[] args) { 12 //1.创建一个集合,存储多个字符串元素 13 ArrayList<String> arrayList=new ArrayList<>(); 14 15 arrayList.add("小龙女"); 16 arrayList.add("张无忌"); 17 arrayList.add("任盈盈"); 18 arrayList.add("张三丰"); 19 arrayList.add("张敏"); 20 arrayList.add("令狐冲"); 21 22 //2.把集合中所有以"张"开头的元素存储到一个新的集合 23 ArrayList<String> zhangList=new ArrayList<>(); 24 for (String s:arrayList) { 25 if (s.startsWith("张")) { 26 zhangList.add(s); 27 } 28 } 29 30 //3.把"张"开头的集合中的长度为3的元素存储到一个新的集合 31 ArrayList<String> threeList=new ArrayList<>(); 32 for (String s:zhangList) { 33 if (s.length()==3) { 34 threeList.add(s); 35 } 36 } 37 38 //4.遍历上一步得到的集合 39 for (String s:threeList) { 40 System.out.println(s); 41 } 42 43 System.out.println("--------"); 44 45 //Stream流改进 46 arrayList.stream().filter(s->s.startsWith("张")).filter(s -> s.length()==3).forEach(System.out::println); 47 } 48 }
Stream流的常见生成方式
Stream流的使用
- 生成流
通过数据源(集合,数组等)生成流
list.stream()
- 中间操作
一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用
filter()
- 终结操作
一个流只能有一个终结操作,当这个操作执行后,流就被使用"光"了,无法再被操作。所以这必定是流的最后一个操作
forEach()
生成Stream流的方式:
(1)Collection体系集合
使用默认方法stream()生成流, default Stream stream()
(2)Map体系集合
把Map转成Set集合,间接的生成流
(3)数组通过Stream接口的静态方法of(T… values)生成流
1 import java.util.*; 2 import java.util.stream.Stream; 3 4 public class StreamDemo { 5 public static void main(String[] args) { 6 //1.Collection体系的集合可以使用默认方法stream()生成流 7 List<String> list=new ArrayList<>(); 8 Stream<String> listStream = list.stream(); 9 10 Set<String> set=new HashSet<>(); 11 Stream<String> setStream = set.stream(); 12 13 //2.Map体系的集合间接的生成流 14 Map<String,String> map=new HashMap<>(); 15 16 //Set<String> set1 = map.keySet(); 可以看出键的集合是Set类型的 17 Stream<String> ketStream = map.keySet().stream(); 18 19 //Collection<String> values = map.values(); 可以看出值的集合是Collection类型的 20 Stream<String> valueStream = map.values().stream(); 21 22 Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream(); 23 24 //3.数组可以通过Stream接口的静态方法of(T... values)生成流 25 String[] strArray = {"hello","world","java"}; 26 Stream<String> array = Stream.of(strArray); 27 28 //也可以: 29 Stream<String> stringStream = Stream.of("hello", "world", "java"); 30 Stream<Integer> integerStream = Stream.of(10, 20, 30, 40); 31 } 32 }
Stream流中间操作方法
概念:
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。
常见方法:
1 Stream filter(Predicate predicate) 用于对流中的数据进行过滤 2 3 Stream limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据 4 5 Stream skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 6 7 static Stream concat(Stream a, Stream b) 合并a和b两个流为一个流 8 9 Stream distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流 10 11 Stream sorted() 返回由此流的元素组成的流,根据自然顺序排序 12 13 Stream sorted(Comparator comparator) 返回由该流的元素组成的流,根据提供的Comparator进行排序 14 15 Stream map(Function mapper) 返回由给定函数应用于此流的元素的结果组成的流 16 17 IntStream mapToInt(ToIntFunction mapper) 返回一个IntStream其中包含将给定函数应用于此流的元素的结果
1 (1)filter代码演示: 2 3 import java.util.ArrayList; 4 5 public class FilterDemo { 6 public static void main(String[] args) { 7 ArrayList<String> list=new ArrayList<>(); 8 9 list.add("林青霞"); 10 list.add("张曼玉"); 11 list.add("王祖贤"); 12 list.add("柳岩"); 13 list.add("张敏"); 14 list.add("张无忌"); 15 16 //需求1:把list集合中以"张"开头的元素在控制台输出 17 list.stream().filter(s->s.startsWith("张")).forEach(System.out::println); 18 System.out.println("--------"); 19 //需求2:把list集合中长度为3的元素在控制台输出 20 list.stream().filter(s->s.length()==3).forEach(System.out::println); 21 System.out.println("--------"); 22 //需求3:把list集合中以张开头的,长度为3的元素在控制台输出 23 list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(System.out::println); 24 } 25 }
1 (2)limit&skip代码演示: 2 3 import java.util.ArrayList; 4 5 public class StreamDemo02 { 6 public static void main(String[] args) { 7 ArrayList<String> list=new ArrayList<>(); 8 9 list.add("林青霞"); 10 list.add("张曼玉"); 11 list.add("王祖贤"); 12 list.add("柳岩"); 13 list.add("张敏"); 14 list.add("张无忌"); 15 16 //需求1:取前3个数据在控制台输出 17 list.stream().limit(3).forEach(System.out::println); 18 System.out.println("--------"); 19 20 //需求2:跳过3个元素,把剩下的元素在控制台输出 21 list.stream().skip(3).forEach(System.out::println); 22 System.out.println("--------"); 23 24 //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出 25 list.stream().skip(2).limit(2).forEach(System.out::println); 26 } 27 }
1 (3)concat&distinct代码演示: 2 3 import java.util.ArrayList; 4 import java.util.stream.Stream; 5 6 public class StreamDemo03 { 7 public static void main(String[] args) { 8 ArrayList<String> list=new ArrayList<>(); 9 10 list.add("林青霞"); 11 list.add("张曼玉"); 12 list.add("王祖贤"); 13 list.add("柳岩"); 14 list.add("张敏"); 15 list.add("张无忌"); 16 17 //需求1:取前4个数据组成一个流 18 Stream<String> s1 = list.stream().limit(4); 19 20 //需求2:跳过2个数据组成一个流 21 Stream<String> s2 = list.stream().skip(2); 22 23 //需求3:合并需求1和需求2得到的流,并把结果在控制台输出 24 //Stream.concat(s1,s2).forEach(System.out::println); //concat是静态方法,通过类名调用 25 26 //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复 27 Stream.concat(s1,s2).distinct().forEach(System.out::println); 28 } 29 }
1 (4)sorted代码演示: 2 3 import java.util.ArrayList; 4 5 public class StreamDemo04 { 6 public static void main(String[] args) { 7 ArrayList<String> list = new ArrayList<String>(); 8 9 list.add("linqingxia"); 10 list.add("zhangmanyu"); 11 list.add("wangzuxian"); 12 list.add("liuyan"); 13 list.add("zhangmin"); 14 list.add("zhangwuji"); 15 16 //需求1:按照字母顺序把数据在控制台输出 17 list.stream().sorted().forEach(System.out::println); 18 19 System.out.println("--------"); 20 21 //需求2:按照字符串长度把数据在控制台输出 22 list.stream().sorted((s1,s2)->{ 23 int num=s1.length()-s2.length(); 24 int num2= num==0?s1.compareTo(s2):num; 25 return num2; 26 }).forEach(System.out::println); 27 } 28 }
1 (5)map&mapToInt代码演示: 2 3 import java.util.ArrayList; 4 5 public class StreamDemo05 { 6 public static void main(String[] args) { 7 ArrayList<String> list = new ArrayList<String>(); 8 9 list.add("10"); 10 list.add("20"); 11 list.add("30"); 12 list.add("40"); 13 list.add("50"); 14 list.add("60"); 15 16 //需求:将集合中的字符串数据转换为整数之后在控制台输出 17 list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println); 18 //list.stream().map(Integer::parseInt).forEach(System.out::println); 19 20 list.stream().mapToInt(s->Integer.parseInt(s)).forEach(System.out::println); 21 22 //int sum() 返回此流中元素的总和,mapToInt的特有方法 23 int result = list.stream().mapToInt(Integer::parseInt).sum(); 24 System.out.println(result); 25 } 26 }
Stream流终结操作方法
概念:
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。
常见方法:
1 void forEach(Consumer action) 对此流的每个元素执行操作
1 long count() 返回此流中的元素数
1 示例: 2 import java.util.ArrayList; 3 4 public class StreamDemo06 { 5 public static void main(String[] args) { 6 //创建一个集合,存储多个字符串元素 7 ArrayList<String> list = new ArrayList<String>(); 8 9 list.add("林青霞"); 10 list.add("张曼玉"); 11 list.add("王祖贤"); 12 list.add("柳岩"); 13 list.add("张敏"); 14 list.add("张无忌"); 15 16 //需求1:把集合中的元素在控制台输出 17 list.stream().forEach(System.out::println); 18 System.out.println("--------"); 19 20 //需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出 21 long counts = list.stream().filter(s -> s.startsWith("张")).count(); 22 System.out.println(counts); 23 } 24 }
Stream流综合练习
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
男演员只要名字为3个字的前三人
女演员只要姓林的,并且不要第一个
把过滤后的男演员姓名和女演员姓名合并到一起
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
1 演员类: 2 public class Actors { 3 private String name; 4 5 public Actors() { 6 } 7 8 public Actors(String name) { 9 this.name = name; 10 } 11 12 public String getName() { 13 return name; 14 } 15 16 public void setName(String name) { 17 this.name = name; 18 } 19 }
1 import java.util.ArrayList; 2 import java.util.stream.Stream; 3 4 public class StreamTest { 5 public static void main(String[] args) { 6 //创建集合 7 ArrayList<String> manList = new ArrayList<String>(); 8 9 manList.add("周润发"); 10 manList.add("成龙"); 11 manList.add("刘德华"); 12 manList.add("吴京"); 13 manList.add("周星驰"); 14 manList.add("李连杰"); 15 16 ArrayList<String> womanList = new ArrayList<String>(); 17 18 womanList.add("林心如"); 19 womanList.add("张曼玉"); 20 womanList.add("林青霞"); 21 womanList.add("柳岩"); 22 womanList.add("林志玲"); 23 womanList.add("王祖贤"); 24 /* 25 //男演员只要名字为3个字的前三人 26 Stream<String> man = manList.stream().filter(s -> s.length() == 3).limit(3); 27 28 //女演员只要姓林的,并且不要第一个 29 Stream<String> woman = womanList.stream().filter(s -> s.startsWith("林")).skip(1); 30 31 //把过滤后的男演员姓名和女演员姓名合并到一起 32 Stream<String> stream = Stream.concat(man, woman); 33 34 //把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据 35 stream.map(Actors::new).forEach(p->System.out.println(p.getName())); 36 */ 37 38 //改进: 39 Stream.concat(manList.stream().filter(s -> s.length()==3), 40 womanList.stream().filter(s -> s.startsWith("林")).skip(1)). 41 map(Actors::new).forEach(p-> System.out.println(p.getName())); 42 } 43 }
Stream流的收集操作
概念:
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。
常用方法:
1 R collect(Collector collector) 把结果收集到集合中
工具类Collectors提供了具体的收集方式:
1 public static Collector toList() 把元素收集到List集合中 2 3 public static Collector toSet() 把元素收集到Set集合中 4 5 public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中
1 示例: 2 import java.util.*; 3 import java.util.stream.Collector; 4 import java.util.stream.Collectors; 5 import java.util.stream.Stream; 6 7 public class CollectDemo { 8 public static void main(String[] args) { 9 /*-------List 10 //创建List集合对象 11 List<String> list = new ArrayList<String>(); 12 13 list.add("林青霞"); 14 list.add("张曼玉"); 15 list.add("王祖贤"); 16 list.add("柳岩"); 17 18 //需求1:得到名字为3个字的流 19 Stream<String> listStream = list.stream().filter(s -> s.length() == 3); 20 21 //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历 22 List<String> names = listStream.collect(Collectors.toList()); 23 for (String name:names) { 24 System.out.println(name); 25 } 26 */ 27 28 29 /*-------Set 30 //创建Set集合对象 31 Set<Integer> set = new HashSet<Integer>(); 32 33 set.add(10); 34 set.add(20); 35 set.add(30); 36 set.add(33); 37 set.add(35); 38 39 //需求3:得到年龄大于25的流 40 Stream<Integer> setStream = set.stream().filter(s -> s > 25); 41 42 //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历 43 Set<Integer> ages = setStream.collect(Collectors.toSet()); 44 for (Integer age:ages) { 45 System.out.println(age); 46 } 47 */ 48 49 //-------Map 50 //定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成 51 String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"}; 52 53 //需求5:得到字符串中年龄数据大于28的流 54 Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28); 55 56 //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值 57 Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1]))); 58 59 Set<String> keySet = map.keySet(); 60 for (String key:keySet) { 61 Integer value = map.get(key); 62 System.out.println(key+","+value); 63 } 64 } 65 }
Collectors.groupingBy();
1 // 1.查询店铺信息 2 List<Shop> list = shopService.list(); 3 // 2.把店铺分组,按照typeId分组,typeId一致的放到一个集合 4 Map<Long, List<Shop>> map = list.stream().collect(Collectors.groupingBy(Shop::getTypeId)); 5 // 3.分批完成写入Redis 6 for (Map.Entry<Long, List<Shop>> entry : map.entrySet()) { 7 // 3.1.获取类型id 8 Long typeId = entry.getKey(); 9 String key = SHOP_GEO_KEY + typeId; 10 // 3.2.获取同类型的店铺的集合 11 List<Shop> value = entry.getValue(); 12 List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(value.size()); 13 // 3.3.写入redis GEOADD key 经度 纬度 member 14 for (Shop shop : value) { 15 // stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString()); 16 locations.add(new RedisGeoCommands.GeoLocation<>( 17 shop.getId().toString(), 18 new Point(shop.getX(), shop.getY()) 19 )); 20 } 21 stringRedisTemplate.opsForGeo().add(key, locations); 22 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY