jdk8新特性Stream基础了解

Java 8 Stream API 基础了解

1.Stream概念
2.数据源
3.中间操作
4.最终操作
5.Stream使用注意事项

1、java.util.stream.Stream概念

*Java API文档解释:支持顺序和并行聚合操作的一系列元素。

*菜鸟教程解释:这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

从菜鸟教程解释中可以看到两个关键词:中间操作、最终操作。Java API的一包操作就是创建类对象,调用方法,所以Stream(流)的使用大概分为三部分:
数据源(通过数据源获取对应的Stream对象)、中间操作、最终操作

Stream主要特征
Pipelining:流水线风格,每个中间操作都会返回流对象本身,这样多个操作就可以可做串连起来的管道,经过管道不同部分时进行不同操作*(官方说法补充:如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。)*

内部迭代:当执行中间操作或最终操作时,Stream会自动将每个数据执行一次中间操作方法。(官方:以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。)

2、数据源

用于生成Stream的数据源有两种:集合(单列、双列集合)、数组

  • 获取流
public static void main(String[] args) {
    /*
	* 1、单列集合Collection:通过调用内部stream()方法获取
	*/
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");
    Stream<String> stream = list.stream();
    stream.forEach(System.out::println);
    System.out.println("---------------------------");

    /*
	* 2、双列集合Map: 通过获取keySet来获取stream,间接获取
	*/
    Map<String, String> map = new HashMap<String, String>();
    map.put("a", "aaaa");
    map.put("b", "bbbb");
    Stream<String> stream2 = map.keySet().stream();
    stream2.forEach(System.out::println);
    System.out.println("---------------------------");

    /*
	* 3、数组,通过Arrays的getStream(数组)获取代表该数据源的stream流
	*/
    String[] strs = {"11111","22222","33333","44444"};
    Stream<String> stream3 = Arrays.stream(strs);
    stream3.forEach(System.out::println);
    System.out.println("---------------------------");

    /*
	* 4、Stream还提供了of(...)静态方法和不确定参数形式,来直接获取一批同类型数据源的stream流
	*/
    Stream<Integer> stream4 = Stream.of(77,88,99);
    stream4.forEach(System.out::println);
    System.out.println("---------------------------");

}
  • 通过代码可以看出,还有一种Stream.of(T … values)不确定参数的方法,该方法可以获取一批同类型的数据源的Stream(流),但实际还是数组,该方法调用的是Arrays.stream()方法,Stream.class源码:
    在这里插入图片描述

  • 而集合使用流的方法都是用的Collection提供的stream()方法。

3、中间操作方法

  • 过滤(filter)

    方法说明
    Stream filter(Predicate predicate)返回由与此给定谓词匹配的此流的元素组成的流。

    Predicate是函数式接口,可以使用Lambda表达式

public static void main1(String[] args) {
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");
    Stream<String> stream = list.stream();//****************************
    /*
	* 1、过滤,对应方法Stream<T> filter(Predicate<? extends T> p)
	*/
    //stream.filter(s->s.startsWith("郭")).filter(s->s.length()==3).forEach(System.out::println);

    //过滤条件对象--Predicate函数式接口,用Lambda表达式创建对象
    Predicate<String> p1 = s->s.startsWith("郭");
    Predicate<String> p2 = s->s.length()==3;
    //过滤出集合中元素字符串中以“郭”开头,并且长度等于3的元素--and
    //stream.filter(p1.and(p2)).forEach(System.out::println);//filter等价于filter(p1).filter(p2)

    //过滤出集合中元素字符串中以“郭”开头,或长度等于3的元素--or
    stream.filter(p1.or(p2)).forEach(System.out::println);
}
  • 截取和跳过(limit、skip)

    方法说明
    Stream limit(long maxSize)截取流的前maxSize个元素形成新的流,
    若maxSize大于原流中数据个数,则只截取原流所有,不报错。
    Stream skip(long n)跳过前n个数据,用后面的数据作为数据源生成新的Stream(流)

测试代码:

public static void main2(String[] args) {
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");
    Stream<String> stream = list.stream();

    //截取流中数据0-2(前两个),生成新的流
    //Stream<String> stream2 = stream.limit(2);
    //stream2.forEach(System.out::println);

    //跳过前2个,将后面的数据生成新的流
    //Stream<String> stream3 = stream.skip(2);
    //stream3.forEach(System.out::println);

    //跳过前2个,截取剩余数据的前2个生成新的流
    stream.skip(2).limit(2).forEach(System.out::println);
}
  • 合并和去重复(concat、distinct)

    方法说明
    Stream concat(Stream a, Stream b)合并a,b两个Stream(流)成一个Stream
    Stream distinct()对流中数据去重复后返回新的Stream

测试代码:

public static void main3(String[] args) {
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");

    Stream<String> s1 = list.stream().limit(4);
    Stream<String> s2 = list.stream().skip(2);

    //将s1,s2连个流合并,打印合并后的流中数据
    //Stream.concat(s1, s2).forEach(System.out::println);

    //将s1,s2连个流合并,打印合并后的流中数据---去除重复数据
    Stream.concat(s1, s2).distinct().forEach(System.out::println);

}
  • 映射(map)

    方法说明
    Stream map(Function mapper)返回由给定函数应用于此流的元素的结果组成的流。

    map(Function f)方法中参数Function是函数式接口,所以可以使用Lambda表达式

测试代码:

public static void main(String[] args) {
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");
    list.stream().map(s->s+"666").forEach(System.out::println);
}

4、最终操作

  • Stream最终操作方法:
方法说明
long count()返回此流中的元素数。
void forEach(Consumer action)对此流的每个元素执行操作。
collect(Collector collector)收集数据并保存到集合
  • Collector提供的方法:
方法说明
public static Collector toList()把元素收集到List集合中
public static Collector toSet()把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

测试代码:

public static void main(String[] args) {
    ArrayList<String> list =new ArrayList<>();
    Collections.addAll(list, "于谦","郭德纲","郭麒麟","孟鹤堂","侯震","岳云鹏","周九良");

    //1、数据遍历(forEach)
    //将中间操作后剩余的数据进行打印,也可以直接打印原流
    list.stream().filter(s->s.length()==2).forEach(System.out::println);
    System.out.println("---------------");
    //将println静态方法使用Lambda表达式格式传入
    list.stream().forEach(System.out::println);
    System.out.println("---------------");

    //2、统计数据个数(count),也可对源流操作
    long count = list.stream().filter(s->s.startsWith("郭")).count();
    System.out.println("姓郭数据个数:"+count);
    System.out.println("---------------");

    //3、收集数据封装到集合(collect)
    List<String> list2 = list.stream().
        filter(s->s.startsWith("郭")).
        collect(Collectors.toList());//封装到List
    System.out.println("List:"+list2);

    Set<String> set = list.stream().
        filter(s->s.startsWith("郭")).
        collect(Collectors.toSet());//封装到Set
    System.out.println("Set:"+set);
}

5、Stream(流)使用注意事项:

  • Stream是按需操作,并不存储数据,所以不会对源数据造成影响。
  • Stream(流)只能进行一次操作,所以在使用时常用链式编程,不声明对象。
  • Stream组成有:数据源、0-n个中间操作、最终操作。
  • 区分中间操作方法很简单,返回结果是Stream的就是中间操作。

Stream使用流程图
在这里插入图片描述

参考博客:

【重学Java】Stream流 - gonghr - 博客园 (cnblogs.com)

JDK8新特性之Stream流学习_zhangjun62的博客-CSDN博客_jdk8stream流

Java 8 新特性 | 菜鸟教程 (runoob.com)

java8 Stream stream().filter()进行迭代及实现机制_cv+攻城狮的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值