JAVA8 Stream接口流式方法 map操作 filter操作以及flatMap操作

 

   关于stream 流式操作,在rt.jar 包里面,ReferencePipeline管道方式操作数据 下面集成所有操作方法,利用这些流,处理大数据的方式,效率提升明显,并且很多语言都支持这种操作,相当于统一了这种编程方式。

   我们先来看看这三个操作过滤的是什么数据,

1,filter操作,我们先看方法的定义 

 源码如下Stream<T> filter(Predicate<? super T> predicate); 一个单纯的过滤操作直接返回传入类型 

String[] dd = { “a”, “b”, “c” };
        Stream<String> stream = Arrays.stream(dd);
        stream.filter(str -> str.equals(“a”)).forEach(System.out::println);//返回字符串为a的值
2.map操作,先看方法定义

源码如下  <R> Stream<R> map(Function<? super T, ? extends R> mapper); 

这个方法传入一个Function的函数式接口,这个接口,接收一个泛型T,返回泛型R,map函数的定义,返回的流,表示的泛型是R对象,这个表示,调用这个函数后,可以改变返回的类型

	public static void main(String[] args) {
		Integer[] dd = { 1, 2, 3 };
		Stream<Integer> stream = Arrays.stream(dd);
		stream.map(str -> Integer.toString(str)).forEach(str -> {
			System.out.println(str);// 1 ,2 ,3
			System.out.println(str.getClass());// class java.lang.String
		});
 
		List<Emp> list = Arrays.asList(new Emp("a"), new Emp("b"), new Emp("c"));
		list.stream().map(emp -> emp.getName()).forEach(str -> {
			System.out.println(str);
		});
 
	}
 
	public static class Emp {
		private String name;
 
		public Emp() {
			super();
		}
 
		public Emp(String name) {
			super();
			this.name = name;
		}
 
		public String getName() {
			return name;
		}
 
		public void setName(String name) {
			this.name = name;
		}
 
	}

可以看到,我们把Integer,变成了String输出,把Emp对象里的name字符串,单独输出;现在,我们只看到了一个forEach的终端操作,后面,我们会看到,更多的终端操作,把map操作后,改变的对象类型,返回各种类型的集合,或者对数字类型的,返回求和,最大,最小等的操作;

 

3.flatMap操作,我们还是先看接口定义   包含前面两种过滤类型

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

这个接口,跟map一样,接收一个Fucntion的函数式接口,不同的是,Function接收的泛型参数,第二个参数是一个Stream流;方法,返回的也是泛型R,具体的作用是把两个流,变成一个流返回,下面,我们看一个案例,来详细解答,怎么把两个流的内容,变成一个流的内容

public static void main(String[] args) {
		String[] strs = { "aaa", "bbb", "ccc" };
		Arrays.stream(strs).map(str -> str.split("")).forEach(System.out::println);// Ljava.lang.String;@53d8d10a
		Arrays.stream(strs).map(str -> str.split("")).flatMap(Arrays::stream).forEach(System.out::println);// aaabbbccc
		Arrays.stream(strs).map(str -> str.split("")).flatMap(str -> Arrays.stream(str)).forEach(System.out::println);// aaabbbccc
	}

 

首先,第二段代码,才输出的具体的字符串;

第一段输出代码里,我们先看map操作,通过上面对map的介绍,我们可以看到,map可以改变返回的Stream的泛型,str.split(“”),根据空字符串分隔,返回的类型是一个数组,返回的流也是Stream<String[]>,而不是Stream<String>;在第二段代码中,数组的流,经过map操作,返回Stream<String[]>后,再经过flatMap,把数组通过Arrays.stream变成一个新的流,再返回到原来的流里;这样,两个流就合并成一个流;第三段代码,是第二段代码的,另一种写法;
 

PS  简单操作示例   1filter 过滤,2 map可以返回其它类型,3 flatMap合并两个流数据

          String[] includes=new String[10];
           includeList.toArray(includes);
           List<String> maplist =  includeList.stream().map(s -> s.equals("a6")?"a6L":s).collect(Collectors.toList());
           List<String> filterlist = includeList.stream().filter(s -> s.equals("a6")).collect(Collectors.toList());
           includeList.stream().map(s -> s.equals("a6")?"a6L":s).forEach(System.out::println);//直接操作里面的数据, 改变逻辑后可以返回list等
           filterlist.forEach(System.out::println);// 只打印a6过滤的数据
           maplist.forEach(System.out::println);
           

4  构造流的几种常见方法


Stream stream = Stream.of("a", "b", "c");

// 2. Arrays

String [] strArray = new String[] {"a", "b", "c"};

stream = Stream.of(strArray);

stream = Arrays.stream(strArray);

// 3. Collections

List<String> list = Arrays.asList(strArray);

stream = list.stream();

 5 流转换为其它数据结构

// 1. Array
String[] strArray1 = stream.toArray(String[]::new);
// 2. Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream.collect(Collectors.toSet());
Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
// 3. String
String str = stream.collect(Collectors.joining()).toString();

一个 Stream 只可以使用一次

很多API都有这种方式的操作,对后期大数据或者其它语言兼容,解决跨语言的问题,也提交了效率,日后要以这种方式处理数据,

6 流的操作

接下来,当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。

Intermediate:  (中间)
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

Terminal:(终端)
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

Short-circuiting:(短路)
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limi

 

limit/skip

limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素(它是由一个叫 subStream 的方法改名而来)。

List<String> personList2 = persons.stream().
map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
 System.out.println(personList2);
  • 所有 Stream 的操作必须以 lambda 表达式为参数
  • merge为Map接口新增的默认方法
   // k-8值存在为value8->执行merge函数->直接返回"NewMerge8"->newValue为"NewMerge8"
        // 执行put->所以这里输出"NewMerge8"
        map.merge(8, "merge", (value, newValue) -> "NewMerge8");
        System.out.println(map.get(8));

// 合并方式
  String newValue2 = map.merge(9, "concat", (value, newValue) -> value.concat(newValue));

// 解释:从字符串序列中过滤出以字符a开头的字符串并迭代打印输出
        stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);

组合查询  主要是peek 监视消费后执行的动作

List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
System.out.println(“sum is:”+nums.stream().filter(num -> num != null).
           distinct().mapToInt(num -> num * 2).
            peek(System.out::println).skip(2).limit(4).sum());

Integer类型的List,获取其对应的Stream对象,然后进行过滤掉null,再去重,再每个元素乘以2,再每个元素被消费的时候打印自身,在跳过前两个元素,最后去前四个元素进行加和运算

 

7 数据并行化操作

Stream 的并行化也是 Java 8 的一大亮点。数据并行化是指将数据分成块,为每块数据分配单独的处理单元。这样可以充分利用多核 CPU 的优势。

并行化操作流只需改变一个方法调用。如果已经有一个 Stream 对象,调用它的 parallel() 方法就能让其拥有并行操作的能力。如果想从一个集合类创建一个流,调用 parallelStream() 就能立即获得一个拥有并行能力的流。

int sumSize = Stream.of("Apple", "Banana", "Orange", "Pear") .parallel() .map(s -> s.length()) .reduce(Integer::sum) .get(); assertEquals(sumSize, 21);

 

详情API参考 https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

 

    原文作者:大树168
    原文地址: https://blog.csdn.net/limingcai168/article/details/85265089
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞