百日筑基第二十七天-Java8 stream流常用操作

打印 上一主题 下一主题

主题 701|帖子 701|积分 2103

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
百日筑基第二十七天-Java8 stream流常用操作

创建stream流的方式

1、通过Collection系列提供的stream()(串行) 或parallelStream()(并行)获取
  1. List<String> list = new ArrayList<>();
  2. Stream<String> stream1 = list.stream();//串行流
  3. Stream<String> stream2 = list.parallelStream();//并行流
复制代码
2、通过Arrays中的静态方法stream() 获取数据流,吸收参数为数组范例,将数组转成流
  1. User[] u = new User[2];
  2. Stream<User> stream3 = Arrays.stream(u);
复制代码
3、通过Stream类中的静态方法of()
  1. Stream<String> stream4 = Stream.of("11","2");
复制代码
4、使用 Pattern.splitAsStream() 方法,将字符串分隔成流
  1. Pattern pattern = Pattern.compile(",");
  2. Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
  3. stringStream.forEach(System.out::println);
复制代码
测试数据

界说一个User 类,用于测试:
  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class User {
  5.     private Integer id;
  6.     private String type;
  7.     private String name;
  8. }
复制代码
添加一些测试数据:
  1. List<User> list = new ArrayList<>();
  2. User user=new User(1,"a","小明");
  3. User user1=new User(2,"a","小红");
  4. User user2=new User(3,"b","小李");
  5. list.add(user);
  6. list.add(user1);
  7. list.add(user2);
复制代码
分组

将List里面的元素,以某个属性来分组,例如,以type分组,将type相同的放在一起
例:
  1. //List 以type分组 Map<String,List<User>>
  2. Map<String, List<User>> groupBy = list.stream().collect(Collectors.groupingBy(User::getType));
  3. System.out.println(groupBy);
复制代码
输出:
  1. {a=[User(id=1, type=a, name=小明), User(id=2, type=a, name=小红)], b=[User(id=3, type=b, name=小李)]}
复制代码
分组个数
我们还可以求出分组个数
求分组个数很简单,我们只需要在groupingBy方法里加多一个Collectors.counting()即可
  1. Map<String, Long> groupBy = list.stream().collect(Collectors.groupingBy(User::getType,Collectors.counting()));
复制代码
输出:
  1. {a=2, b=1}
复制代码
多级分组
多级分组是先将stream流分组,然后再对分组后的数据再进行分组
例:
  1. Map<String, Map<String, List<User>>> groupBy = list.stream().collect(Collectors.groupingBy(User::getType,Collectors.groupingBy(User::getName)));
复制代码
输出:
  1. {a={小明=[User(id=1, type=a, name=小明)], 小红=[User(id=2, type=a, name=小红)]}, b={小李=[User(id=3, type=b, name=小李)]}}
复制代码
Stream转换List

很多时间,我们对Stream操作之后,返回的还是Stream流,很多时间,我们想返回的List或者其他范例的对象,我们就需要对Stream流进行终止操作
方法:.collect(Collectors.toList())
阐明:由Stream中的值生成一个List列表,也可用collect(toSet())生成一个Set集合。
例:
  1. String[] testStrings = { "a", "b", "c", "d" };
  2.                
  3. List<String> list = Stream.of(testStrings).collect(Collectors.toList());
复制代码
Stream转换Set

Stream 转换为 Set,Set不允许重复值,没有序次,使用collect(Collectors.toSet())即可
例:
  1. Set<User> collect = list.stream().collect(toSet());
复制代码
Stream转换Map

Stream 转换为 Map,使用.collect(Collectors.toMap())即可。
Collectors.toMap 有三个重载方法:
  1. toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
  2. toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
  3.         BinaryOperator<U> mergeFunction);
  4. toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,
  5.         BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
复制代码
参数含义分别是:
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 辩论时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
三种重载方法,所以就有三种差别的用法
1、只指定key和value的映射
例:
  1. //以ID为key,User对象为value组成一个map
  2. Map<Integer, User> collect1 = list.stream().collect(toMap(User::getId, userObject -> userObject));
  3. collect1.entrySet().stream().forEach(System.out::println);
复制代码
输出:
  1. 1=User(id=1, type=a, name=小明)
  2. 2=User(id=2, type=a, name=小红)
  3. 3=User(id=3, type=b, name=小李)
复制代码
当然,你也可以指定某个属性为value值
例:
  1. //以ID为key,Name为value
  2. Map<Integer, String> collect1 = list.stream().collect(toMap(User::getId, User::getName));
复制代码
2、使用第二个重载方法,需要传多一个参数,即需要传入合并函数(用于当发生key辩论时,如何处置惩罚,即插入一个key已经存在的数据时的处置惩罚)
例:传入(o,n)->o合并函数
  1. Map<String, String> collect1 = list.stream().collect(toMap(User::getType, User::getName,(o,n)->o));
  2. //遍历map
  3. collect1.entrySet().stream().forEach(System.out::println);
复制代码
o,n)->o:此中o和n表示旧的value和新的value,只是一个名称,可以随意换成其他的名称,->o表示保存旧的value值,不插入新的value值
如我们运行上面的例子,输出如下
  1. a=小明
  2. b=小李
复制代码
我们的数据中type值相同的有两个,由于小明是先插入的,所以合并函数(o,n)->o保存的是先插入的数据
如果我们想用后插入的数据来替换旧的数据,那么只需要把返回变量变一下即可,如下
  1. (o,n)->n
复制代码
当然,我们还可以返回其他情势的value,比如拼接两个value等等操作
例:
  1. (o,n)->o+n
复制代码
3、调用第三个重载方法,需要传4个参数,即在合并函数之后,再传入一个函数,用于自界说返回 Map的 范例
我们看一下三个参数的tomap源码
  1. public static <T, K, U> Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) {
  2.         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
  3.     }
复制代码
可以看到,其实就是使用四个参数的重载方法,只不过替我们默认界说了返回的map范例为HashMap
有时间,我们不想返回HashMap,我们想返回ConcurrentHashMap,很简单,如下
  1. list.stream().collect(toMap(User::getType, User::getName,(o,n)->o,ConcurrentHashMap::new));
复制代码
如果想返回TreeMap,那么将ConcurrentHashMap::new替换成TreeMap::new即可
自界说实现Collection的数据结构网络

除了使用Collectors提供了toMap,toList等方法之外,我们还可以自界说Collection的数据结构网络
例:
  1. //用LinkedList收集
  2. list.stream().collect(Collectors.toCollection(LinkedList::new));
  3. //用TreeSet收集
  4. list.stream().collect(Collectors.toCollection(TreeSet::new));
复制代码
stream字符串拼接

stream字符串拼接使用Collectors.joining()方法就可将字符串拼接在一起,而且joining方法可以传入一个字符参数,如许就可以在拼接的每个元素中心都拼接上该字符
注:joining方法只对String范例的流有效
joining还有一个三个传参的重载方法,
  1. public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
复制代码
参数阐明:
delimiter:元素隔断字符
prefix:前缀,即拼接字符开头加上的字符
suffix:后缀,即拼接字符末端加上的字符
例:
  1. List<String> stringList = Arrays.asList("a", "b", "c");
  2. System.out.println(stringList.stream().collect(joining()));
  3. System.out.println(stringList.stream().collect(joining("xxx")));
复制代码
例:
  1. List<String> stringList = Arrays.asList("a", "b", "c");
  2. System.out.println(stringList.stream().collect(joining()));
  3. System.out.println(stringList.stream().collect(joining("xxx")));
复制代码
输出:
  1. a
  2. b
  3. c
  4. axxxbxxxc
复制代码
排序

stream流中的排序方法为sorted()
sorted(),产生一个新流,此中按自然序次排序。
sorted(Comparator),产生一个新流,此中按Comparator比较器序次排序。
注:如果是自界说的对象使用sorted()方法,需要实现Comparable 接口,基本范例可以直接使用。
  1. Comparable接口只有一个compareTo方法
  2. public interface Comparable<T>{
  3. int compareTo(T t);
  4. }
复制代码
int compareTo(T t)方法阐明
界说:比较此对象与指定对象的序次。
返回:负整数、零或正整数。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
例:
  1.    //按ID降序
  2.    @Override
  3.     public int compareTo(User user) {
  4.         return user.id-this.id;
  5.     }
复制代码
升序
  1. this.id-user.id
复制代码
如果我们不想在对象里实现Comparable 接口,那么可以使用sorted(Comparator)方法,传入参数为Comparator比较器
例:根据type进行排序,reversed()为倒序
  1. list.stream().sorted(Comparator.comparing(User::getType).reversed()).collect(toList());
复制代码
注:comparing方法是Comparator内部实现的一个方法,我们可以传入某个属性,然后会替我们生成一个该属性的升序Comparator比较器
总数

求一个stream的长度,使用.collect(Collectors.counting()即可
  1. list.stream().collect(Collectors.counting())
复制代码
循环遍历

循环遍历使用forEach方法即可
  1. //循环遍历输出每个元素
  2. collect.stream().forEach(System.out::println);
复制代码
取最大值

stream流有一个max方法可以取出stream流中符合要求的最大值
max方法源码如下:
  1. Optional<T> max(Comparator<? super T> var1);
复制代码
传入的参数为Comparator比较器,返回的是一个Optional对象,使用Optional的get方法,即可取出封装的对象
如果是基本类,则可以使用基本范例的compare方法
例:
  1. //使用Comparator的comparing方法做参数
  2. User user3 = list.stream().max(Comparator.comparing(User::getId)).get();
  3. //取出User集合中最大的ID
  4. Integer max = list.stream().map(x -> x.getId()).max(Integer::compare).get();
复制代码
取最小值

stream流有一个min方法可以取出stream流中符合要求的最小值
用法和max方法一样
例:
  1. //取出id最小的user
  2. User min = list.stream().min((u1,u2)->u1.getId().compareTo(u2.getId())).get();
复制代码
注:上面使用的是lambda表达式的Comparator比较器
取平均值

取平均值有averagingInt,averagingLong,averagingDouble三种方法,只是范例不一样,返回的都是Double
averagingInt源码如下
  1. public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)
复制代码
例:
  1. //取出id的平均值
  2. list.stream().collect(Collectors.averagingInt(User::getId));
复制代码
筛选

stream流的筛选方法为filter(predicate)
filter(predicate)-吸收lambda,从流中排除某些元素,保存符合条件的元素
该方法担当一个谓词predicate方法(返回Boolean的函数)作为参数
例:
  1. //筛选出id大于1的user
  2. List<User> collect2 = list.stream().filter(x -> x.getId() > 1).collect(toList());
复制代码
输出
  1. User(id=2, type=a, name=小红)
  2. User(id=3, type=b, name=小李)
复制代码
留意:stream流的filter方法是保存符合条件的元素
去重

stream流的筛选方法为distinct(),它会根据元素的hashcode()和equals()去除重复的元素
例:
  1. List<String> stringList = Arrays.asList("a", "b", "c","a");
  2. stringList.stream().distinct().forEach(System.out::println);
复制代码
输出:
  1. a
  2. b
  3. c
复制代码
可以看到重复的元素a只剩下了一个
截断流limit

limit(n)-截断流,使其元素不超过给定命量
源码如下
  1. Stream<T> limit(long var1);
复制代码
传入的是一个Long范例的整数
例:
  1. stringList.stream().limit(2L);
复制代码
使用了这个limit方法后,stream流就会只剩下2个元素
映射

Stream中包罗5个映射方法:map、mapToDouble、mapToInt、mapToLong和flatMap。
map,吸收Lambda,将元素转换成其他情势或提取信息。吸收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
map最常用的操作就是取出元素中的某个属性,形成一个新的流
例:
  1. //将Uer集合中的Name属性全部取出来形成一个新的流,再转换成集合
  2. List<String> nameList = list.stream().map(User::getName).collect(toList());
复制代码
mapToDouble/mapToInt/mapToLong,吸收一个函数作为参数,该函数会被应用到每个元素上,产生一个新DoubleStream/IntStream/LongStream。
匹配

anyMatch是否有一个元素匹配条件,返回的是一个boolean范例元素
源码如下:
  1. boolean anyMatch(Predicate<? super T> var1);
复制代码
例:
  1. //判断是否有元素的type等于b
  2. boolean anyMatch = list.stream().anyMatch(x -> x.getType().equals("b"));
复制代码
allMatch,查抄是否匹配所有元素,需要stream流的所有元素都匹配条件才返回true
noneMatch,查抄是否没有匹配所有元素。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

梦应逍遥

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表