java8新特性Stream流

1.什么是Stream

流(Stream)中保存对集合数组数据的操作

日常工作中,经常需要对集合中的元素进行相关操作。如:增加、删除、获取元素、遍历

2.流式思想

注意:Stream流和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象。

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不会保存数据,而是对数据进行加工处理。Stream 可以看做是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

3.获取Stream流的两种方式

两种常用的方式:
1.集合.stream()方法来获取流;数组则:Arrays.stream(数组)
2.使用Stream.of(集合)获取流

//方式1:根据Collection获取流
//Collection接口中有一个默认的方法:default Stream<E> stream()
//1.List获取流
List<String> list = new ArrayList<>();
Stream<String> stream01 = list.stream();

//2.Set获取流
Set<String> set = new HashSet<>();
Stream<String> stream02 = set.stream();

//3.Map获取流
//  Map并没有继承自 Collection 接口,所有无法通过该 map.stream()获取流。
// 但是可用通过如下三种方式获取:
Map<String,String> map = new HashMap<>();
Stream<String> stream03 = map.keySet().stream();
Stream<String> stream04 = map.values().stream();
Stream<Map.Entry<String, String>> stream05 = map.entrySet().stream();

//方式2:Stream中的静态方法of获取流
//1.字符串获取流
Stream<String> stream06 = Stream.of("aa", "bb", "cc");
//2.数组类型(基本类型除外)
String[] strs = {"aa","bb","cc"};
Stream<String> stream07 = Stream.of(strs);
//3.基本数据类型的数组
int[] arr = {1,2,3,4};
//看着没报错,但是看到返回值是 int[],这是 Stream流把整个数组看做一个元素来操作,而不是操作数组中的int元素(这样子是不行的)
Stream<int[]> stream08 = Stream.of(arr);

4.Stream流常用方法

Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种类型:

方法名

方法作用

返回值类型

方法种类

forEach

遍历(逐一处理)

void

终结

count

统计个数

long

终结

filter

过滤

Stream

函数拼接

limit  

取用前几个

Stream

函数拼接

skip

跳过前几个

Stream

函数拼接

map  

映射

Stream

函数拼接

concat

组合

Stream

函数拼接

终结方法:返回值类型不再是Stream类型的方法,不再支持链式调用。在此终结方法包括 count() 和 forEach() 方法;

        非终结方法:又叫函数拼接方法。值返回值类型仍然是 Stream 类型的方法,支持链式调用(除了终结方法外,其与方法均为非终结方法)      

  提醒:以下所有代码部分,能简化部分尽量简化,均使用最简格式。

      4.1 foreach

        void forEach(Consumer<? super T> action);

        1.forEach()方法用来遍历流中的数据,是一个终结方法。
        2.该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理。

        

        示例如下:

List<String> names = new ArrayList<>();
Collections.addAll(names,"张无忌","周芷若","杨逍","张强","张三丰","赵敏");

//未简写
names.forEach((String str)->{
    System.out.println(str);
});

//简写1
names.forEach(str-> System.out.println(str));

//最终简写
names.forEach(System.out::println);
       
         4.2 count

        long count();

        1.count()方法,用来统计集合中元素个数,是一个终结方法。

        2.该方法返回一个long值代表元素个数。

        

        示例如下:

        

List<String> names = new ArrayList<>();
Collections.addAll(names,"张无忌","周芷若","杨逍","张强","张三丰","赵敏");

//count()计算集合中元素个数
long count = names.stream().count();
System.out.println("元素个数为: "+count);  //元素个数为:6
        4.3  filter


       Stream<T> filter(Predicate<? super T> predicate);

        1.filter()方法,用于过滤数据,返回符合过滤条件的数据,是一个非终结方法。
        2.可以通过filter()方法将一个流转换成另一个子集流。
        3.该接口接收一个Predicate函数式接口参数(可以是一个Lambda表达式或方法引用)作为筛选条件。
        4.因为filter()是一个非终结方法,所以必须调用终止方法。
      

          示例如下:

        

List<String> names = new ArrayList<>();
Collections.addAll(names,"张无忌","周芷若","杨逍","张强","张三丰","赵敏");

//filter()过滤,返回以"J"开头的名字
names.stream()
        .filter(str->str.startsWith("J"))
        .forEach(System.out::println);

//使用BiPredicate,就搞复杂了,如下,没啥意思(只会让人看不懂,哈哈)
BiPredicate<String,String> consumer = String::startsWith;
names.stream()
        .filter(str-> consumer.test(str,"张"))
        .forEach(System.out::println);
        4.4  limit


        Stream<T> limit(long maxSize);

        1.limit()方法,用来对Stream流中的数据进行截取,只取用前n个,是一个非终结方法。
        2.参数是一个long型,如果集合当前长度大于参数则进行截取,否则不进行操作。因为limit()是一个非终结方法,所以必须调用 终止方法。


          示例如下:

List<String> names = new ArrayList<>();
Collections.addAll(names,"张无忌","周芷若","杨逍","张强","张三丰","赵敏");

//limit()截取,截取list集合前三个元素
names.stream().limit(3).forEach(System.out::println);
          4.5 skip

        Stream<T> skip(long n);

        1.skip()是跳过前几个元素,去取后面的元素,获取一个截取之后的新流,它是一个非终结方法。
        2.参数是一个long型,如果Stream流的当前长度 > n,则跳过前n个,否则将会得到一个长度为0的空流。
        3.因为 limit() 是一个非终结方法,所以必须调用终止方法。
       

         示例如下:

        

List<String> names = new ArrayList<>();
Collections.addAll(names,"张无忌","周芷若","杨逍","张强","张三丰","赵敏");

//skip()跳过list集合前2个元素,获取剩下的元素
names.stream().skip(2).forEach(System.out::println);


备注:
使用 skip() 和 limit() 方法,即可实现类似分页的操作了。示例如下:
//一页10条 分页操作
//第一页
skip(0).limit(10)
//第二页
skip(10).limit(10)
//第三页
skip(20).limit(10)
...
        4.6 map


        <R> Stream<R> map(Function<? super T, ? extends R> mapper);

        1.map() 方法,可以将流中的元素映射到另一个流中。即:可以将一种类型的流转换为另一种类型的流。
        2.该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
        3.map() 方法是一个非终结方法,所以必须调用终止方法。
        

        示例如下:

        

List<String> list = new ArrayList<>();
Collections.addAll(list,"11","22","33","44","55");

//通过map()方法,可以将String类型的流转换为int类型的流
list.stream().map((String str)->{
        return Integer.parseInt(str);
}).forEach((Integer num) -> {
        System.out.println(num);
});

//简化
list.stream().map(str->Integer.parseInt(str)).forEach(str->System.out.println(str));

//简化后
list.stream().map(Integer::parseInt).forEach(System.out::println);

        4.7 concat 


        public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
            Objects.requireNonNull(a);
            Objects.requireNonNull(b);
 
            @SuppressWarnings("unchecked")
            Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
            Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
            return stream.onClose(Streams.composedClose(a, b));
        }

        1.concat()方法,可将两个Stream流合并成一个流进行返回。如果是三个流,则需要两两合并,不能一次性合并三个流。
        2.concat()方法是Stream接口的静态方法,可以直接使用 类名.方法名 调用。


        注意:
        concat()方法此处接收的是Stream类型,不能接收IntStream等类型。
        concat()是一个静态方法,与java.lang.String中的concat()方法是不同的。
               

        示例如下:

        

 //concat()方法
Stream<Integer> aStream = Stream.of(1, 2, 3);
Stream<Integer> bStream = Stream.of(4, 5, 6);

//合并a、b流
Stream<Integer> concatStream = Stream.concat(aStream, bStream);
concatStream.forEach(System.out::println);


  

        4.8 sorted


        sorted()方法,可以用来对 Stream 流中的数据进行排序。sorted()方法共有以上两种情况:

        (1)根据元素的自然规律排序,默认升序
        Stream<T> sorted();

        (2)根据比较器指定的规则排序
        Stream<T> sorted(Comparator<? super T> comparator);

        因为 sorted() 方法是一个非终结方法,所以必须调用终止方法。

        示例代码:

        

//sorted():根据元素的自然规律排序
Stream<Integer> stream01 = Stream.of(66,33,11,55);
stream01 .sorted().forEach(System.out::println);

//sorted(Comparator<? super T> comparator):根据比较器规则升序排序
Stream<Integer> stream02 = Stream.of(66,33,11,55);
stream02.sorted((a,b) -> a-b).forEach(System.out::println);
//根据比较器规则降序排序
stream02.sorted((a,b) -> b-a).forEach(System.out::println);

4.9 distinct


        Stream<T> distinct();
       1. distinct()方法,可以用来去除重复数据。
       2.因为distinct()方法是一个非终结方法,所以必须调用终止方法。

        去除重复数据,此处有几种情况:
        (1)基本类型去重
        (2)String类型去重
        (3)引用类型去重(对象去重)

        提示:
        第(1)(2)使用 distinct()方法可以直接去重
        第(3)对象类型需要重写 equals() 和 hasCode() 方法,使用 distinct() 方法才能去重成功。


        示例如下:
        

        

//基本类型去重
Stream<Integer> stream01 = Stream.of(66,33,11,55,33,22,55,66);
stream01.distinct().forEach(System.out::println);

//字符串去重
Stream<String> stream02 = Stream.of("AA","BB","AA");
stream02.distinct().forEach(System.out::println);

//自定义对象去重
//Person对象类,有String name,Integer age 两个属性,两参数构造器,get/set()方法,重写了equals(),hashCode(),toString()方法。此处就不附Person实体类了)
BiFunction<String,Integer,Person> p = Person::new;
Person p1 = p.apply("西施", 18);
Person p2 = p.apply("貂蝉", 20);
Person p3 = p.apply("王昭君", 22);
Person p4 = p.apply("杨玉环", 23);
Person p5 = p.apply("杨玉环", 23);
Stream<Person> stream03 = Stream.of(p1, p2, p3, p4, p5);
//去重复对象
stream03.distinct().forEach(System.out::println);
4.10  match


        //allMatch 全匹配(匹配所有,所有元素都需要满足条件-->返回true)
        boolean allMatch(Predicate<? super T> predicate);
        //anyMatch 匹配某个元素(只要有一个元素满足条件即可-->返回true)        
        boolean anyMatch(Predicate<? super T> predicate);
        //noneMatch 匹配所有元素(所有元素都不满足指定条件-->返回true)
        boolean noneMatch(Predicate<? super T> predicate);

        1.match()方法,可以用来判断 Stream 流中的数据是否匹配指定的条件。
        2.allMatch()、anyMatch()、noneMatch()方法都是终结方法,返回值为boolean。


        示例如下:
        

        

Stream<Integer> stream01 = Stream.of(5, 3, 6, 1);
boolean allMatch = stream01.allMatch(i -> i > 0);
System.out.println("allMatch匹配:"+allMatch);

Stream<Integer> stream02 = Stream.of(5, 3, 6, 1);
boolean anyMatch = stream02.anyMatch(i -> i > 5);
System.out.println("anyMatch匹配:"+anyMatch);

Stream<Integer> stream03 = Stream.of(5, 3, 6, 1);
boolean noneMatch = stream03.noneMatch(i -> i < 3);
System.out.println("noneMatch匹配:"+noneMatch);


        结果:
        allMatch匹配:true
        anyMatch匹配:true
        noneMatch匹配:false


        4.11 max / min


        Optional<T> max(Comparator<? super T> comparator);
        Optional<T> min(Comparator<? super T> comparator);

        1.max()和min()方法,用来获取Stream流中的最大值和最小值。
        2.该接口需要一个Comparator函数式接口参数,根据指定排序规则来获取最大值、最小值。

        为了保证数据的准确性,此处排序规则需要是升序排序。因为:max() 方法获取的是排序后的最后一个值,min() 方法获取的是排序后的第一个值。如果使用降序排序后,那么 max() 和 min() 方法就相反了,就有异常了。

        

        示例如下:

        

        

//max()
Stream<Integer> stream01 = Stream.of(33, 11, 22, 5);
Optional<Integer> max = stream01.max((i1, i2) -> i1 - i2);
System.out.println("最大值:"+max.get());

//min()
Stream<Integer> stream02 = Stream.of(33, 11, 22, 5);
Optional<Integer> min = stream02.min((i1, i2) -> i1 - i2);
System.out.println("最小值:"+min.get());

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值