1.8新特性——Stream流

Stream

 在Java1.8中,由于lambda表达式这种函数式编程 JDK引入了一个新概念stream流。用于解决已有集合类库的一些弊端。

代码如下:

public class Test10 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("abc123");
        list.add("aaa22");
        list.add("bcd132");
        list.add("ccccead");
        list.add("bbb230");

        list.stream()
                .filter(s -> s.contains("1"))
                .filter(s -> s.length() <= 6)
                //void forEach(Consumer<? super T> action) 对此流的每个元素进行操作
                //借助于Consumer中的accept(T t)打印输出
                .forEach(s -> System.out.println(s));
    }
}

流式思想概述

当需要多个元素进行操作的时候,尤其是多部操作,考虑到性能以及便利性。首先需要考虑一个“模型”步骤方案。

方案中操作的每一个步骤,我们称之为一个“流”,调用指定的API方法,从一个流转换为另一个流。

对应的API方法,filter、map、skip、count都是对函数模型进行操作。

当我们使用一个流的时候,通常需要包含三个基本步骤:①获取一个数据源②数据转换③执行操作获取想要的结果。每次转换原有的Stream对象,返回一个新的Stream对象。这样我们可以像链条一样进行操作。

Stream流和以往的Collection集合有所不同。stream操作有两个基础的特征:

  • 中间操作都会返回流对象本身,这样多个操作可以串联成一个管道,如同流式操作进行优化,比如可以延迟执行和短路。
  • 内部迭代:以前对集合遍历都是迭代器iterator或者增强for循环,显示的在集合外部进行迭代。这叫做外部迭代。Stream流提供了内部迭代的方法,这个流可以直接调用遍历的方法。

Stream流 其实是一个集合元素的函数模型,他并不是集合,也不是数据结构。其本身并不存储任何元素(地址值)。

Stream流是一个来自数据源的元素队列:

  • 元素是特定类型的对象,形成一个队列。Java 当中的Stream并不会存储元素,而是按需计算。
  • 数据源:流的来源。可以是集合,也可以是数组等容器。

获取流对象

获取一个流对象,有以下常见的操作:

  • 所有的Collection集合都可以通过stream() 默认方法来获取。
  • Stream接口里面含有一个静态方法of 也可以获取对应的流对象
public static void main(String[] args) {
		// 把集合转换为Stream流
		List<String> list = new ArrayList<>();
		Stream<String> stream1 = list.stream();
		
		HashSet<Integer> set = new HashSet<>();
		Stream<Integer> stream2 = set.stream();
		
		HashMap<String, String> map = new HashMap<>();
		// map中的key存储到一个set中
		Set<String> keySet = map.keySet();
		Stream<String> stream3 = keySet.stream();
		
		// 把map中的value值存储到一个Collection集合中
		Collection<String> values = map.values();
		Stream<String> stream4 = values.stream();
		
		// 把map中的key和value值一起存储到entry(键与值的映射)中
		Set<Entry<String,String>> entrySet = map.entrySet();
		Stream<Entry<String, String>> stream5 = entrySet.stream();
		
		// 把数组转换为Stream流
		Stream<Integer> stream6 = Stream.of(1,2,3,4,5,6);
		
		stream6.filter(num -> num > 3).filter(num -> num % 2 == 0).forEach(num -  >System.out.println(num));
		
		// 可变参数是一个数组
		String[] arr = {"a","b","c","d"};
		Stream<String> stream7 = Stream.of(arr);
	}

Stream流中的常用方法

流模型的操作很多,大致上可分为两部分:

  • 延迟方法: 返回值类型都是Stream接口本身,因此可支持链式操作。
  • 终结方法:返回值类型不是Stream接口本身,不支持链式操作,例如:count方法和forEach方法。

forEach方法

void forEach(Consumer<T> consumer);//借助于该函数接口中的方法acceot方法
// Consumer<T> 是一个消费型接口 用来消费一个指定泛型的数据。

代码如下:

public class TestforEach{
	public static void main(String[] args){
		Stream<String> stream = Stream.of("","","","","");
		stream.forEach(str ->{
			if(str.contains("a")){
				System.out.println(str);
			}
		})
	}
}

过滤:filter

可以通过filter方法将一个流转换成另一个子集流。

Stream<T> filter(Predicate<? super T> predicate) 返回由此给定谓词匹配的此流的元素组成的流。
//借助于Predicate函数式接口当中的抽象方法 test(T t) 对数据进行过滤

该方法接受一个函数式接口predicate,可以使用lambda表达式进行条件的筛选。

Predicate接口

java.util.stream.Predicate函数式接口。其中唯一的抽象方法

boolean test(T t),该方法会返回布尔类型值,代表指定的条件是否满足,如果条件满足返回true,那么Stream流的方法filter将集合或者数组其中的元素保留下来,如果条件不满足返回false,那么filter方法会舍弃该元素。

代码如下:

public static void main(String[] args) {
		// 1、 准备一个数据源
		// 获取该数据源
		String[] arr = {"小孙","小王","小赵","老王","涂少","老刘"};
		// 2. 数据转换
		// 使用Stream流中的方法filter,对姓涂的人过滤掉
		Stream<String> stream = Stream.of(arr);
		Stream<String> stream2 = stream.filter(name -> !name.contains("涂"));
		Stream<String> stream3 = stream2.filter(name -> name.startsWith("小"));
		stream3.forEach(name ->System.out.println(name));
		stream2.filter(name -> !name.contains("少")).forEach(name ->System.out.println(name));
		 
		/* Stream流属于管道流,每次只能被消费一次
		 * 第一个Stream流调用完毕后,数据就会被转换到下一个Stream上
		 * 而这时第一个Stream流已经使用完毕,就会关闭了。
		 * 所以第一个Stream就不能再调用方法了。
		 * 如果你强制调用方法,程序就会抛出非法状态异常
		 * java.lang.IllegalStateException: stream has already been operated upon or closed
		 * stream.filter(name -> !name.contains("涂"))
		      .filter(name -> name.startsWith("小"))
		      .forEach(name ->System.out.println(name));
		*/
	}

映射:map

如果你需要将流中的数据映射到另一个流中,可以使用map方法。

<R> Stream<R> map(Function<? super T ,? extents R> mapper)返回由给定函数应用于此流的元素的结果组成的流。

该方法接受一个函数式接口function作为方法参数,可以将当前流中的T数据转换成另外一种R类型的数据。

Function接口

java.util.stream.Function函数式接口。其中唯一的抽象方法:

R  apply(T t)
// 可以将一种T类型的数据转换成R类型的数据,那么这种转换的动作,我们称之为"映射"

代码如下:

public static void main(String[] args) {
		// 1. 准备一个数据源
		// 获取数据源
		// 把String字符串的整数-->int类型的整数
		Stream<String> stream = Stream.of("123","124","125","126","120");
		// 2. 数据转换 把字符串类型的数据转换成int类型的数据 由于Function是一个函数式接口,所以可以使用Lambda表达式
		// apply(T t) 
		//Stream<Integer> stream2 = stream.map(str -> Integer.valueOf(str));
		Stream<Integer> stream2 = stream.map((String str) -> {
			return Integer.valueOf(str);
		});
		// 遍历
		stream2.forEach(num -> System.out.println(num));
	}

统计个数:count

可以像Collection集合当中的size()一样,统计流中的元素个数,通过count方法来实现。

// 返回此流中的元素数。 
long count();

该方法返回一个long类型的值代表流中的元素个数(区别于size()返回值int值)

代码如下:

public class Demo01Count {
    public static void main(String[] args) {
      Stream<Integer> stream =  Stream.of(1,2,3,4,5,6);
      // 统计个数
      long count =   stream.count();
      System.out.println(count);// 6  
    } 
}

取用流中前几个:limit

limit() 方法可以对流中的数据进行限制、截取操作,需要一个参数max,设定取用流中前max个数。

Stream<T> limit(long maxSize)  //返回由此流的元素组成的流,截短长度不能超过 maxSize 。  

参数是一个long类型的,截取的长度不能超过流中最大元素个数;否则不进行操作。
代码如下:

public class Demo02Limit {
    public static void main(String[] args){
        // 准备一个数据源
        // 获取数据源
       Stream<Integer> stream =  Stream.of(12,13,14,15,16,20,30);
       // 想要截取流中的前五个元素
       Stream<Integer> stream02  = stream.limit(5);
       // 查看流中的元素个数
        System.out.println(stream02.count());// 5
    }   
}

跳过前几个:skip

Stream<T> skip(long n) // 在丢弃流的第一个 n元素后,返回由该流的 n元素组成的流。

如果流中的当前个数小于n,你将会得到一个长度为0的空流;反之流中的个数大于n,则会跳过前n个元素。

代码如下:

在这里插入代码片public static void main(String[] args) {
		// 1.
		String[] source = {"123","124","125","126","abc","abd","abe"};
		Stream<String> stream = Stream.of(source);
		// 2. 跳过前3个元素
		Stream<String> stream2 = stream.skip(source.length+1);// 空流
		// 3. 
		//stream2.forEach(str -> System.out.println(str));// abc abd abe
		long count = stream2.count();
		System.out.println(count);// 0
	}

组合:concat

在这里插入代码片// 创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。 
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) 

代码如下:

在这里插入代码片public class Demo04Concat {
    public static void main(String[] args){
        // 准备二个数据源
        // 获取两次数据源
       Stream<Integer> stream   =   Stream.of(12,13,14,15,16,20,30);
       Stream<Integer> stream02 =   Stream.of(1,2,3,4,5,6,7);
       // 把两个流合并成一个流
       Stream<Integer> stream03 =   Stream.concat(stream,stream02); 
       stream03.forEach(num -> System.out.print(num + " "));
       //展示结果: 12,13,14,15,16,20,30,1,2,3,4,5,6,7  
    }   
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值