Stream流是Java 8新加入的最常用的流接口,位于java.util.stream包下(java.util.stream.Stream ),这并不是一个函数式接口,接口里面包含了很多抽象方法,这些方法对于Stream流的操作都是至关重要的,最常见的方法有filter、map、foreach、count、limit、skip、concat
获取Stream流的两种方法
- 所有的 Collection 集合都可以通过 stream 默认方法获取流,stream()方法是Collection集合接口的一个默认方法,需要注意的是Map集合接口并不是Collection接口的子接口,所以不能直接调用stream方法获取Stream流,但是却可以分别对key和value获取Stream流;
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
Stream<Integer> stream = list.stream();
Set<String> set=new HashSet<String>();
set.add("aa");
set.add("bb");
set.add("cc");
Stream<String> stream = set.stream();
Map<String, String> map=new HashMap<String, String>();
map.put("name", "xiaoming");
map.put("sex", "man");
Stream<String> stream1 = map.keySet().stream();
Stream<String> stream2 = map.values().stream();
- Stream 接口的静态方法 of 可以获取数组对应的流,of 方法的参数其实是一个可变参数,所以支持数组。
Stream<Integer> stream5 = Stream.of(1,2,3);
String[] array={"aa","bb","cc"};
Stream<String> stream6 = Stream.of(array);
Stream流常用方法
对于Stream流的常用方法,可以分成延迟方法和终结方法
- 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,支持链式调用(除了终结方法外,其余方法均为延迟方法)
- 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持链式调用。常见的终结方法有 count 和forEach 方法
1. foreach:遍历(对流中的元素进行遍历)
void forEach(Consumer<? super T> action);
该方法接收一个Consumer函数式接口,方法返回值是void,并非Stream接口,所以属于终结方法;
2. filter:过滤(对流进行一个过滤操作,只保留满足条件的元素)
Stream<T> filter(Predicate<? super T> predicate);
该方法接收一个Predicate函数式接口,方法返回值是Stream接口,还可以进行链式调用,所以属于延迟方法;Predicate接口中的唯一抽象方法——test方法将会产生一个boolean值结果,代表指定的条件是否满足。如果结果为true,那么Stream流的 filter 方法将会留用元素;如果结果为false,那么 filter 方法将会舍弃元素;
String[] array = {"xiaoming","xiao","hong"};
Stream<String> stream1 = Stream.of(array);
Stream<String> stream2 = stream1.filter(s->s.length()>4);//过滤出长度大于4的字符串
stream2.forEach(s->System.out.println(s));//xiaoming
3. map:映射(将流中的元素映射到另一个流中)
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该方法接收一个Function函数式接口,方法返回值是Stream接口,还可以进行链式调用,所以属于延迟方法;Function接口中的唯一抽象方法——apply方法接收一个参数并返回一个参数,也就是可以将一种T类型转换成为R类型,而这种转换的动作,就称为“映射”;
Stream<Integer> stream1 = Stream.of(1,2,3);
//将原来流中int类型元素映射为String类型
Stream<String> stream2 = stream1.map(i->String.valueOf(i));
stream2.forEach(s->System.out.println(s));
4. count:统计(计算流中元素个数)
long count();
该方法返回值是long不是int,这一点需要注意,另外方法返回值是long,并非Stream接口,所以属于终结方法;
Stream<Integer> stream = Stream.of(1,2,3);
long count = stream.count();
System.out.println(count);//3
5. limit:(截取流中前几个元素)
Stream<T> limit(long maxSize);
如果集合当前长度大于参数则进行截取;否则不进行操作,也就是返回原来的流对象,并不会报错
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Stream<Integer> stream2 = stream1.limit(3);
stream2.forEach(s->System.out.println(s));//1 2 3
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Stream<Integer> stream2 = stream1.limit(10);
stream2.forEach(s->System.out.println(s));//1 2 3 4 5
6. skip:(跳过流中前几个元素)
Stream<T> skip(long n);
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流;
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Stream<Integer> stream2 = stream1.skip(3);
stream2.forEach(s->System.out.println(s));//4 5
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Stream<Integer> stream2 = stream1.skip(10);
stream2.forEach(s->System.out.println(s));//没有任何输出,也就是得到的是一个空流
7. concat:组合(组合两个流)
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
该方法是Stream接口中的一个静态方法。
Stream<Integer> stream1 = Stream.of(1,2);
Stream<Integer> stream2 = Stream.of(3,4);
Stream<Integer> stream3 = Stream.concat(stream1, stream2);
stream3.forEach(s->System.out.println(s));//1 2 3 4
Stream流编程需要注意的点
Stream流属于管道流,只能被消费一次,也就是说第一个Stream流调用方法完毕之后,数据会流到下一个Stream流,并且该流会被关闭,再次使用该流去调用方法将会报错
public class Main {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1,2,3,4,5);
long count = stream.count();//第一次使用stream流
stream.forEach(s->System.out.println(s));//第二次使用stream流
}
}
关于jdk1.8的其它新特性:
- jdk1.8新特性——Lambda表达式与函数式接口:https://blog.csdn.net/can_chen/article/details/106886385
- jdk1.8新特性——Optional类:https://blog.csdn.net/can_chen/article/details/106886579
- jdk1.8新特性——方法引用:https://blog.csdn.net/can_chen/article/details/106886536