Java8新特性(二)—— Stream的使用
一、什么是Stream
类似Iterator,可以对一个集合中的各个元素进行遍历,并执行某些操作。但与Iterator不同的是,首先Stream不需要显示的对每个元素逐个进行处理,只需指定要执行的操作例如“获取每个字符串的首字母”、“过滤掉长度大于10的字符串”,Stream会隐式的对元素进行遍历筛选,最后在需要的时候返回结果。其次相比于Iterator的串行操作而言,Stream支持并行化操作,不需要每个元素读完再读取下一个,而可以将数据分成多段,每一段在不同的线程中处理,然后将结果一起输出。
二、Stream的特点及操作分类
1)Stream的特点
- Stream不是数据结构,不会保存数据。Stream中的数据只能遍历处理一次,遍历过一次就用尽了。
- Stream不会修改原来数据流中的数据,每次操作完之后会生成新的Stream对象。
- Stream的操作是懒执行的,只有最终结果需要的时候才执行。
2)Stream的操作分类:
Stream的操作可以分为中间操作(Intermediate operations)、终端操作(Terminal operations)两种操作,其中中间操作又可以分为无状态和有状态操作,终端操作又可以分为非短路操作和短路操作。
Stream操作分类 |
||
中间操作 (Intermediate operations) |
无状态 |
unordered()、filter()、map()、mapToInt()、mapToLong()、 mapToDouble()、flatMap()、flatMapToInt()、flatMapToLong() flatMapToDouble()、peek() |
有状态 |
distinct()、sorted()、limit()、skip() |
|
终端操作 (Terminal operations) |
非短路操作 |
forEach()、forEachOrdered()、toArray()、reduce()、collect()、 max()、min()、count() |
短路操作 |
anyMatch()、allMatch()、noneMatch()、findFirst()、findAny() |
- 中间操作:中间操作是指操作期间只是对操作进行了记录,结束操作时才会触发实际的计算。
- 无状态操作:元素的处理不受之前元素的影响。
- 有状态操作:该操作只有拿到所有元素之后才可以继续执行。
- 终端操作:一个Stream对象只能有一个终端操作,指最后需要真实处理数据的操作,一旦发生,就会生成对应的处理结果。
- 非短路操作:指必须处理完所有元素才能得到最终结果。
- 短路操作:指遇到某些符合条件的元素就可以得到最终结果。
三、Stream的创建方式
1)使用of方法:用于为给给定元素创建顺序留,可以传递单个元素或多个元素,元素类型可以为基本数据类型也可以为其他类型
例1:创建字符串流
public class StreamExercise {
static Stream<String> stream = Stream.of("Red","Blue","Green");
public static void main(String[] args) {
stream.forEach(System.out::println);
}
}
执行结果:
例2:创建对象流
public class StreamExercise {
public static void main(String[] args) {
Stream<User> userStream = Stream.of(
new User("Aaron", 22),
new User("Alice", 20),
new User("Amy", 25)
);
userStream.forEach(u -> System.out.println(u.getUserName()));
}
}
class User {
private String userName;
private int age;
public User(String userName, int age) {
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
例3:创建Int、Double、Long的流,需要使用IntStream.of/DoubleStream.of/LongStream.of方法
public class StreamExercise {
public static void main(String[] args) {
System.out.println("--- IntStream ---");
IntStream intStream = IntStream.of(1, 2, 3);
intStream.forEach(System.out::println);
System.out.println("--- LongStream ---");
LongStream longStream = LongStream.of(100L, 200L, 300L);
longStream.forEach(System.out::println);
System.out.println("--- DoubleStream ---");
DoubleStream doubleStream = DoubleStream.of(123.45, 456.78, 789.12);
doubleStream.forEach(System.out::println);
}
}
- 使用集合和数组自带的stream( )方法创建流
例:
public class StreamExercise {
public static void main(String[] args) {
//String类型
String[] characters = {"Java8", "In", "Action"};
Stream<String> stream1 = Arrays.stream(characters);
stream1.forEach(System.out::println);
//Integer类型
Integer[] numbers = {1, 3, 5, 7, 9};
Stream<Integer> stream2 = Arrays.stream(numbers);
stream2.forEach(System.out::println);
}
}
public class StreamExercise {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("python");
list.add("c++");
list.add("c");
list.add("sql");
Stream<String> listStream = list.stream();
listStream.forEach(System.out::println);
}
}
- 使用generate( )或Stream.iterate( )方法创建无限流
例1:generate( )方法接受一个参数函数
public class StreamExercise {
public static void main(String[] args) {
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
}
}
执行结果:
例2:iterate( )方法接受一个初始值,还有一个应用在每个新生成的数值上的函数
public class StreamExercise {
public static void main(String[] args) {
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
}
}
执行结果:
四、Stream常用方法举例
中间无状态操作:
- filter( ): 筛选出符合条件的元素
例:
public class StreamExercise {
public static void main(String[] args) {
Stream.iterate(0, n -> n + 2)
.limit(10)
.filter(i -> i > 5)
.forEach(System.out::println);
}
}
结果:
- map( ): 对一个流中的值进行某种转换。需要传递一个转换的函数作为参数
例:
public class StreamExercise {
public static void main(String[] args) {
Stream.iterate(0, n -> n + 2)
.limit(10)
.map(i -> i / 2)
.forEach(System.out::println);
}
}
结果:
- flatmap( ): 使用一个函数作为参数,将流中的每个值替换为另一个流,然后把所有流连接成一个流。
public class StreamExercise {
public static void main(String[] args) {
Stream<String> flatMapStreamObj = Stream.of("a,b,c", "a,e,f", "g,h,i");
flatMapStreamObj.flatMap(str -> {
String[] arr = str.split(",");
return Arrays.stream(arr);
}).forEach(System.out::println);
}
}
结果:
中间有状态操作:
- limit(n)和skip(n)方法:limit方法返回一个包含n个元素的新的流;skip方法返回一个丢弃前面n个元素的新的流。使用方法上面例子中已经包含了,在此不额外举例。
- distinct( ):根据原始流中的元素返回一个具有相同顺序、去除了重复数据的流。该方法使用较简单,在此不举例。
- sorted( ):返回排序后的流
例:
public class StreamExercise {
public static void main(String[] args) {
Stream<String> flatMapStreamObj = Stream.of("a,b,c", "a,e,f", "g,h,i");
flatMapStreamObj.sorted().forEach(System.out::println);
}
}
结果:
- 点赞
- 收藏
- 关注作者
评论(0)