关于java8新特性 Stream流的常规用法总结

一、stream 的种类

  • stream有两种流

一种是串行流–Collection.Stream() --常用的
另一个是并行流–Collection.parallelStream()
所有Collection集合的实现类都继承了这两个方法
两者的使用场景是:

  1. 单核 cpu 环境,不推荐使用 parallel stream,在多核 cpu 且有大数据量的条件下,推荐使用 paralle stream;
  2. 并行流parallel stream 底层使用的是 JVM 的 ForkJoinPool,在cpu恰好将线程分配到多个核心的条件下,可以达到一个很高的运行效率;
  3. Parallel Stream 受引 CPU 环境影响很大,当没分配到多个cpu核心时,加上引用 forkJoinPool 的开销,运行效率可能还不如普通的 Stream;

二、 stream 流的多种获取方式

1)从 Collection 和 数组中获取
Collection.stream()
Collection.parallelStream()
Arrays.stream(T array)
Stream.of()

 //(1)Stream.of方法
Stream<String> stream = Stream.of("hello", "xxx", "yyy", "beijing", "shanghai");

//(2)Arrays.stream方法
IntStream stream = Arrays.stream(new int[]{100, 200, 300, 400});

//(3)iterate迭代 --从0开始,循环10个数,每个数+2打印出来,打印的是0,2,4....18
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(10).forEach(System.out::println);

2)从BufferedReader中获取
java.io.BufferedReader.lines()

3)静态工厂
java.util.stream.IntStream.range()
java.nio.file.Files.walk()

4)自己构建
java.util.Spliterator

5)其它
Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()

三、流的操作类型简介

【—中间操作—】

一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历,这被称为“惰性求值”。

操作操作说明
map (mapToInt, flatMap 等)转换或映射。将数据从一种格式转换成另一种格式。
peekl与map用法类似,但是map会改变元素本身,peek不改变元素本身(对象的话会改变)
filter过滤,从流中排除元素
distinct筛选,通过流所生成元素的 equals() 去除重复元素
sorted排序
limit限制返回个数
skip删除集合对象前n个元素,跳过元素
unordered不关心集合的顺序,例如Stream.distinct就是可以从中获益

—终端操作—

通常分为最终的消费:比如foreach 之类的归纳:collect等 两大类
forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator。

需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream
IntStream、LongStream、DoubleStream。当然我们也可以用 Stream、Stream >、Stream,但是 boxing 和 unboxing 会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。

1)中间操作示例

        List<User> userList = new ArrayList<>();
        User A = new User ();
        A.setName("zhangsan");
        A.setSex("boy");
        A.setMobilephone("111");
        User B = new User ();
        B.setName("lisi");
        B.setSex("girl");
        A.setMobilephone("222");
        User C = new User ();
        C.setName("aoteman");
        C.setSex("girl");
        C.setMobilephone("333");
        userList.add(A);
        userList.add(B);
        userList.add(C);
1.1 map 转换
  • map里面的方法必须是有返回值的,比如get方法
  • new User()方法等,set方法这种返回void的不能在map中使用,否则会报错!
//获取名字集合
List<String> names= resultItems.stream().map(User::getName).collect(Collectors.toList());

//依次打印名字
userList.stream().map(e->e.getName()).forEach(System.out::println);

//名字全部大写
userList.stream().map(e->e.getName().toUpperCase()).forEach(System.out::println);
  • mapToInt
//IntStream求和
int sum = userList.stream().mapToInt(user -> Integer.valueOf(user.getMobilephone())).sum();
  • flatMap 流的扁平化
    map只是一维一对一的映射
    但是flatMap可以把二维的集合映射成一维的
//["Hello","World"]  输出 HeloWrd
String[] words = new String[]{"Hello","World"};
List<String> collect = Arrays.stream(words).map(word -> word.split(""))
.flatMap(Arrays::stream).distinct().collect(toList());

 collect.forEach(System.out::print);
 //输出HeloWrd
1.2 peek

peek 操作接收的是一个 Consumer< T > 函数。peek 操作会按照 Consumer< T > 函数提供的逻辑去消费流中的每一个元素,同时有可能改变元素内部的一些属性

Consumer< T > :消费就是 “用掉” ,返回的是 void

  • peek接收一个Consumer,而map接收一个Function
  • Consumer是没有返回值的,它只是对Stream中的元素进行某些操作,但是操作之后的数据并不返回到Stream中,所以Stream中的元素还是原来的元素。peek-String不会发生变化 , 而peek-Object会发生变化
  • 而Function是有返回值的,这意味着对于Stream的元素的所有操作都会作为新的结果返回到Stream中。
//peek-String不会变化,输出的依然是小写
Stream.of("one", "two").peek(u -> u.toUpperCase()) .forEach(System.out::println);
输出:
one
two

//map 输出的都是大写
Stream.of("one", "two").map(u -> u.toUpperCase()) .forEach(System.out::println);
输出:
ONE
TWO

//peek-Object会发生变化  设置性别都是boy
List<User> boy = userList.stream().peek(user -> user.setSex("boy")).collect(Collectors.toList());
boy.stream().map(User::getSex).forEach(System.out::println);
输出:
boy
boy
1.3 filter 筛选
//筛选女生的姓名集合并打印
userList.stream().filter(u -> "girl".equals(u.getSex())).map(user -> user.getName()).forEach(System.out::println);
1.4 distinct 去除集合中的重复元素

如果集合中是对象,那么对象要重写equals()方法方可达到去重效果
集合中是基本数据类型,直接去重即可

        //第一个map和第三个mao重复,去重处理
        ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
        HashMap<String,String> map1 = new HashMap<>();
        map1.put("name","paidaxing");
        map1.put("age","18");
        mapList.add(map1);

        HashMap<String,String> map2 = new HashMap<>();
        map2.put("name","haimianbobo");
        map2.put("age","16");
        mapList.add(map2);

        HashMap<String,String> map3 = new HashMap<>();
        map3.put("name","paidaxing");
        map3.put("age","18");
        mapList.add(map3);

        mapList.stream().distinct().forEach(System.out::println);
        
        输出:
        {name=paidaxing, age=18}
        {name=haimianbobo, age=16}
1.5 sorted 排序

使用stored()方法排序有两种方法:

  1. stored():默认使用自然序排序, 其中的元素必须实现Comparable接口,适用基本数据类型
  2. sorted(Comparator<? super T> comparator) :我们可以使用lambada 来创建一个Comparator实例。
    实现方法有两种:
    1)JavaBean(数据)实现Compareable
    2)使用sorted()方法时通过Lambda表达式传入自定义比较器
//------------------------------自然排序---------------------------------------------------
Stream.of("bbb","ddd","aaa","ccc").sorted().forEach(System.out::println);
输出:
aaa
bbb
ccc
ddd
//--------------------------------简单Lambda表达式------------------------------------
ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
HashMap<String,String> map1 = new HashMap<>();
map1.put("name","paidaxing");
map1.put("age","18");
mapList.add(map1);
HashMap<String,String> map2 = new HashMap<>();
map2.put("name","haimianbobo");
map2.put("age","16");
mapList.add(map2);
HashMap<String,String> map3 = new HashMap<>();
map3.put("name","paidaxing1");
map3.put("age","21");
mapList.add(map3);
//按照年纪升序排序,自然排序        
mapList.stream().sorted((mapOne,mapTwo) -> Integer.compare(Integer.valueOf(mapOne.get("age")),Integer.valueOf(mapTwo.get("age")))).forEach(System.out::println);
输出:
{name=haimianbobo, age=16}
{name=paidaxing, age=18}
{name=paidaxing1, age=21}

//按照年纪降序排序
mapList.stream().sorted((mapTwo,mapOne) -> Integer.compare(Integer.valueOf(mapOne.get("age")),Integer.valueOf(mapTwo.get("age")))).forEach(System.out::println);

//---------------------------------Lambda表达式传入自定义比较器----------------------------------
userList.stream().sorted((o1,o2)->{
                    int n1=o1.getAge()-o2.getAge();
                    int n2=Double.compare(o1.getSalary(), o2.getSalary());
                    return n1==0?n2:n1; }).forEach(System.out::println);
1.6 limit 限制使其元素不超过给定数量
        ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
        HashMap<String,String> map1 = new HashMap<>();
        map1.put("name","paidaxing");
        map1.put("age","18");
        mapList.add(map1);

        HashMap<String,String> map2 = new HashMap<>();
        map2.put("name","haimianbobo");
        map2.put("age","16");
        mapList.add(map2);

        HashMap<String,String> map3 = new HashMap<>();
        map3.put("name","paidaxing1");
        map3.put("age","21");
        mapList.add(map3);

        mapList.stream().limit(2).forEach(System.out::println);
        输出:
        {name=paidaxing, age=18}
        {name=haimianbobo, age=16}
1.7 skip 删除集合前n个参数,若流中元素不足 n 个,则返回一个空流
mapList.stream().skip(2).forEach(System.out::println);
输出:
{name=paidaxing1, age=21}

2)终端操作示例

2.1 anyMatch/allMatch/noneMatch(匹配)

返回值均为boolean类型

allMatch():检查是否匹配所有元素
anyMatch():检查是否至少匹配一个元素
noneMatch():检查是否没有匹配的元素

//是否其中有女生
boolean b = userList.stream().anyMatch(user -> “girl”.equals(user.getSex()));
System.out.println(b);
输出:true

//是否全部都是女生
boolean b = userList.stream().allMatch(user -> “girl”.equals(user.getSex()));
System.out.println(b);
输出:false

//是不是没有女生
boolean b = userList.stream().noneMatch(user -> “girl”.equals(user.getSex()));
System.out.println(b);
输出:false

2.2 findFirst/findAny 返回流中的一个元素,返回类型均为Optional类型的

Optional类:Java 8 中为了解决空指针异常而引入的类。

findFirst():返回第一个元素
findAny():返回当前流中的任意元素,findAny() 方法在串行和并行流中返回任意一个数据时,总是返回最快得到的那个元素。

取第一个用户的名称
Optional first = userList.stream().findFirst();
User user = first.get();
System.out.println(user.getName());

2.3 min/max (最值) 参数为Comparator类型

//设置值
ArrayList<HashMap<String,String>> mapList = new ArrayList<>();
HashMap<String,String> map1 = new HashMap<>();
map1.put(“name”,“paidaxing”);
map1.put(“age”,“18”);
mapList.add(map1);
HashMap<String,String> map2 = new HashMap<>();
map2.put(“name”,“haimianbobo”);
map2.put(“age”,“16”);
mapList.add(map2);
HashMap<String,String> map3 = new HashMap<>();
map3.put(“name”,“paidaxing1”);
map3.put(“age”,“21”);
mapList.add(map3);

//查询最大年纪的
Optional<HashMap<String, String>> max1 = mapList.stream().max((mapOne, mapTwo) -> Integer.compare(Integer.valueOf(mapOne.get(“age”)), Integer.valueOf(mapTwo.get(“age”))));
System.out.println(max1.get());

2.4 reduce (规约/聚合)

reduce 作用是把 Stream 元素组合起来。它提供一个起始值,然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce

//字符串拼接
String reduce = userList.stream().map(u -> u.getName()).reduce("name: ", (x, y) -> x + y);
System.out.println(reduce);
输出:
name: zhangsanlisiaoteman

//数值求和 10+20+30+40 = 100
List list= Arrays.asList(20,30,40);
Integer sum = list.stream().reduce(10, (x, y) -> x + y);
System.out.println(sum);

//数值求和 10+20+30+40 = 100
List list= Arrays.asList(20,30,40);
Integer sum = list.stream().reduce(10, Integer::sum);
System.out.println(sum);

2.5 Collect (把数据按照指定的集合类型进行返回)
  • 名称大写并转成list 【Collectors.toList()】

List collect = userList.stream().peek(u -> u.setName(u.getName().toUpperCase())).collect(Collectors.toList());
collect.stream().map(User::getName).forEach(System.out::println);
输出:
ZHANGSAN
LISI
AOTEMAN

  • 名称用逗号拼接 【 Collectors.joining(“,”)】

String collect = userList.stream().map(User::getName).collect(Collectors.joining(“,”));
System.out.println(collect);
输出:
zhangsan,lisi,aoteman

  • List转为Map 【Collectors.toMap() 】

1、指定key-value,value是对象中的某个属性值。
Map<Integer,String> userMap1 = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
2.1、指定key-value,value是对象本身,User->User 是一个返回本身的lambda表达式
Map<Integer,User> userMap2 = userList.stream().collect(Collectors.toMap(User::getId,User->User));
2.2、指定key-value,value是对象本身,Function.identity()是简洁写法,也是返回对象本身
Map<Integer,User> userMap3 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
3、指定key-value,value是对象本身,key 冲突的解决办法,这里选择第二个key覆盖第一个key。
Map<Integer,User> userMap4 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity(),(key1,key2)->key2));

  • 按照指定的属性分组 【Collectors.groupingBy()】

返回一个Map,键为分组条件;
值为一个单列集合Collection,表示满足分组条件的元素
//按照性别分组
Map<String, List> collect = userList.stream().collect(Collectors.groupingBy(user -> user.getSex()));
collect.keySet().stream().forEach(System.out::println);
输出:
girl =[User{name=‘lisi’, sex=‘girl’}, User{name=‘aoteman’, sex=‘girl’}]
boy =[User{name=‘zhangsan’, sex=‘boy’}]

  • 按照指定的条件分区 【Collectors.partitioningBy()】

Map<Boolean, List> collect = userList.stream().collect(Collectors.partitioningBy(user -> user.getSex().equals(“girl”)));
collect.keySet().stream().forEach(System.out::println);
输出:
true=[User{name=‘lisi’, sex=‘girl’}, User{name=‘aoteman’, sex=‘girl’}]
false =[User{name=‘zhangsan’, sex=‘boy’}]

Stream stream = Stream.of(“John”, “Baby”, “Lisa”, “张三”, “李四”);
final Map<Boolean, List> map = stream.collect(Collectors.partitioningBy(s -> {
int code = s.codePointAt(0);
// 如果是英文字母,划分到true分组
return (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
}));
// 输出分组结果
map.forEach((isEnglishName, names) -> {
if (isEnglishName) {
System.out.println(“英文名称:”);
} else {
System.out.println(“中文名称:”);
}
names.forEach(name -> System.out.println(“\t” + name));
});
输出:
中文名称:
张三
李四
英文名称:
John
Baby
Lisa

———————————————————————————
参考文章链接:
https://blog.csdn.net/Vaingloryss/article/details/99704860
https://blog.csdn.net/vx539413949/article/details/124180037

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值