Stream 流引入说明
这是java8 引入的新的特性
和之前介绍的java IO 流多多少少有所区别。简单的说IO就是进行了基本的数据传输操作,Stream是对集合的数据进行过滤操作。主要就是对集合进行操作。IO涉及比较广,主要还是进行数据的传输。
相比较集合的话就是一般是配合使用的。集合是用来对数据进行一个存储,不会对数据进行其它形式的处理,主要就是存储。Stream是会对数据处理的,判断,过滤,计算都有。
一般在对集合中的数据进行处理的话,结合Stream可以非常方便进行操作。我们一般还是配合Lambda表达式的模式进行处理。代码比较简化优雅。
Stream 流的常用方法说明
1: filter()
filter(Predicate<? super T> predicate)
返回由与此给定谓词匹配的此流的元素组成的流。
会返回判断条件为true的元素,这个方法会返回一个流
如下,我们先用filter 来返回判断结果为true的流,然后再调用collect中的方法让它返回集合。
ArrayList<String> list = new ArrayList<>(); list.add("林青霞"); list.add("张曼玉"); list.add("王祖贤"); list.add("张敏"); list.add("张无忌"); List<String> list_ = list.stream().filter(s -> s.startsWith("张")).collect(Collectors.toList());
2:collect()
至于collect方法,我们主要需要了解它的一些用法。
collect(Collector<? super T,A,R> collector)
1.Collectors.toList():转换成List集合。/ Collectors.toSet():转换成set集合。
List<String> list_de = list.stream().collect(Collectors.toList());
2:Collectors.toCollection(TreeSet::new):转换成特定的set集合。
TreeSet<String> treeset = list.stream().collect(Collectors.toCollection(TreeSet::new));
3:Collectors.toMap(keyMapper, valueMapper, mergeFunction):转换成map
这个方法包含三个重载方法
toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper); toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction); toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 冲突时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
需要注意的是如果键出现重复或者值为空的时候可能出现异常.所以再转换map的时候可以对值得冲突首先做处理.
简单举例
先创建一个类,Student_clo
package Stream; public class Student_clo<S, I extends Number, S1> { private String name; private Integer age; private String id; public Student_clo(S jgdabc, I i, S snka) { this.name = (String) jgdabc; this.age = (Integer) i; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } } **测试类的使用**
package Stream; import java.util.ArrayList; import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; public class Student_Collection { public static void main(String[] args) { // Student_clo student_clo = new Student_clo(); // Student_clo student_1_clo = new Student_clo(); // Student_clo student_2_clo = new Student_clo(); ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3); student.add(new Student_clo<>("jgdabc",12,"snka")); student.add(new Student_clo<>("jgdb",13,"45")); student.add(new Student_clo<>("sjns",19,"asjsa")); // v1,v2 这边对可能出现的键冲突进行了处理,只是用一下方法 student.stream().collect(Collectors.toMap(Student_clo::getAge, Student_clo::getName,(v1,v2)->v2)); } }
3:distinct()
3:distinct() 方法
这个方法得作用是比较简单的,就是用来去除重复的元素。操作对象也是为流对象。
4:sorted()/sorted()
4: sorted()/sorted(T,T)->int)
方法的主要作用就是实现一个排序。如果流中的元素实现了Comparable接口,有自己的排序规则,就可以直接调用sorted() 方法,如果没有实现排序接口,那么需要调用sorted((T,T)->int )去实现排序接口。
定义一个基本类
package Stream; public class Student_clo<S, I extends Number, S1> { private String name; private Integer age; private String id; public Student_clo(S jgdabc, I i, S snka) { this.name = (String) jgdabc; this.age = (Integer) i; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
package Stream; import javax.sound.midi.Soundbank; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; public class Student_Collection { public static void main(String[] args) { // Student_clo student_clo = new Student_clo(); // Student_clo student_1_clo = new Student_clo(); // Student_clo student_2_clo = new Student_clo(); ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3); student.add(new Student_clo<>("jgdabc",12,"snka")); student.add(new Student_clo<>("jgdb",11,"45")); student.add(new Student_clo<>("sjns",19,"asjsa")); List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).collect(Collectors.toList()); for(Student_clo l: list_sort) { System.out.println(l.getAge()+l.getName()); } System.out.println(list_sort); } }
5: limit()
5:limit(long n)
返回前n个元素,也就是对处理返回的元素做一个限制
List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).limit(2).collect(Collectors.toList());
6:skip()
6:skip(long n)
这个方法是用来过滤掉前n个元素,也可以认为是跳过
List<Student_clo<String, Integer, String>> list_sort = student.stream().sorted((p1,p2)->p1.getAge()-p2.getAge()).limit(2).skip(1).collect(Collectors.toList());
7:forEach()
7:forEach() 方法
该方法可用于对集合进行一个遍历输出
8:map()
8:映射(转换):map
实现将流中的元素映射到另一个流当中
其中接口类型为Function,在写lambda需要注意一下泛型接口就可以
list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println);
9:count()
9:count()
也可以认为是一个终结方法,主要是对元素进行计数,例如返回的的计数。比较简单,对象当然还是操作在Stream流上。
10:concat()
10:concat()方法
对流进行一个合并
// 取前四个数据组成一个流 Stream<String> s1 = list.stream().limit(4); //跳过两个数据组成一个流 Stream<String> s2 = list.stream().skip(2); //合并需求两个流 Stream.concat(s1,s2).forEach(System.out::println);
11:flatMap()
11:flatMap()
对比map 方法的话,区别在于如果map中有流中嵌套了,那么一次遍历是得不到想要的结果的,需要两次遍历,如果我们要flapMap它只需要一次遍历,也就是它会把每个流打开,那么当然只需要一次遍历。
12: peek()
12 peek() peek 函数会按照消费接口Consumer函数进行消费处理,并可以改变函数的一些属性。
list.stream().peek(s-> System.out.println(s)); list.stream().peek(System.out::print); list.stream().peek(StringBuffer::new);
13:iterate()
13:iterate() 方法
返回有序无限连续 Stream由函数的迭代应用产生 f至初始元素 seed ,产生 Stream包括 seed , f(seed) , f(f(seed)) ,等
Stream.iterate(0,x->x+1).limit(6).forEach(System.out::println); //0,1,2,3,4,5
14: reduce()
14: reduce() 方法
对集合形成的流对象进行一个归约
使用 associative累积函数对此流的元素执行 reduction ,并返回描述减小值的 Optional (如果有)。
8的api说的十分精准而难懂。
我们可以用它来做对集合形成的流对象中的元素进行求和。
ArrayList<Integer> list_i = new ArrayList<>(); list_i.add(1); list_i.add(2); list_i.add(3); Integer sum = list_i.stream().reduce(0, Integer::sum); System.out.println(sum);//6
15: max()/min()
15: max()/min() 方法
还是操作流对象,只不过可以用这个方法来进行获取最大的对象,继而获取值。
先定义了一个Student_clo类
package Stream; public class Student_clo<S, I extends Number, S1> { private String name; private Integer age; private String id; public Student_clo(S jgdabc, I i, S snka) { this.name = (String) jgdabc; this.age = (Integer) i; this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
ArrayList<Student_clo<String,Integer,String>> student = new ArrayList<>(3); student.add(new Student_clo<>("jgdabc",12,"snka")); student.add(new Student_clo<>("jgdb",11,"45")); student.add(new Student_clo<>("sjns",19,"asjsa")); Optional<Student_clo<String, Integer, String>> max = student.stream().max((e1, e2) -> e1.getAge() - e2.getAge()); System.out.println(max.get().getAge());//返回到最大年龄为19
16:allMatch()/anyMatch()/noneMatch()
16:allMatch()/anyMatch()/noneMatch()
很明显就是作为匹配,分别对应全部匹配,一个或者一个以上的匹配,不匹配。如果满足对应的条件,就返回True,反之,返回false。
具体去用的话就十分清楚明了。
boolean b = list_i.stream().allMatch(i -> i > 0); boolean b1 = list_i.stream().anyMatch(i -> i > 2); boolean b2 = list_i.stream().noneMatch(i -> i - 3 >= 0);
创建Stream 流
通过Collection集合提供的stream()方法
在介绍方法的上面已经说明了。就是Collection集合系列。基本该说的都说了。前面运用的方法基本都是在集合的基础上进行说明。
Stream<String> stream2 = list.stream();
使用数组
用流将数组包围起来以后,就可以更加方便的使用一些方法(Stream流上的一些处理)
String arr[] = {"jgdabc","dnkas","esfnsa"}; Stream<String> arr1 = Stream.of(arr); Stream<String> limit = arr1.limit(1); limit.forEach(System.out::println);
也可以使用数组中的方法去转换为stream流
final IntStream stream1 = Arrays.stream(new int[]{1, 2, 3});
Stream.iterate()
完整格式
Stream.iterate(final T seed, final UnaryOperator f)
基本在方法说明上也说了。
从参数上具体分析的话,就是一个常量seed,可指定泛型,然后呢,生成到f,f是UnaryOpeartor类型的。
这个类型是什么呢?查看源码的话,还是返现也就是一个继承Function的接口,然后里面有一个静态的方法。
很明显的就是一个函数式接口,稍微了解下就好。
@FunctionalInterface public interface UnaryOperator<T> extends Function<T, T> { /** * Returns a unary operator that always returns its input argument. * * @param <T> the type of the input and output of the operator * @return a unary operator that always returns its input argument */ static <T> UnaryOperator<T> identity() { return t -> t; } }
具体使用这个iterate的时候也就可以正如上面方法中提到的。做到一个类似遍历取值的效果。
Stream.iterate(0, n -> n + 1).limit(5).forEach(a -> { System.out.println(a);//0,1,2,3,4 });
Stream.generate()
其实和iterate一样创建的是无限流。
怎么体现,随机数生成,就可以体现。因为无限流的特点,一般需要用limit()去进行限制。配合使用。还是挺好玩的。只要了解到lambda,函数式编程,好奇的话,看看源码,接口,就完事。
如果你不限制的话,生成时不会结束的。有趣。
Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(10));
限制一下
Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(10)).limit(10); stream.forEach(e -> System.out.println(e));
parallelStream(并行流)
我们也可以去用一个并行流
其实这个流,可以直接放在集合这边去归结,但是感觉这个并行流还是十分有特点的。并行的一个流,采用了多线程的方式。既然采用多线程,那么如果我foreach()进行终结遍历stream所包含的集合的元素,那么一个输出无需。为了好区分,避开使用set集合去验证这个特点。
ArrayList<String> list = new ArrayList<>(); list.add("10"); list.add("20"); list.add("30"); list.add("13"); list.add("50"); Integer arr[] = {1,2,3,4}; list.parallelStream().forEach(System.out::println);
并行可以提高效率,原理使用的还是forkjoin线程池。就简单介绍一下。从集合Collection的并行流的这个方法一直追溯源码的话,会一直找到其实是使用了forkjoin线程池。