1、流的特点
流只能遍历一次,流中的元素向流水线一样经过一个或多个中间操作,最后执行终端操作,完成流的遍历。
流采用内部迭代。
2.流的操作 类型
中间操作—— 返回一个stream,同一个stream可以进行多个中间操作。
filter:过滤操作,filter函数接收一个Lambda表达式作为参数,该表达式返回boolean;
map:转换操作,map函数将stream的元素转换成另一种类型输出;
distinct:去重操作,去除stream中的重复元素;
limit:截取操作,截取流的前N个元素;
skip:跳过操作,跳过流的前n个元素;
flatMap:合并操作,将小流合并成一个大流;
sorted:排序操作,根据传入的排序规则排序;
peek:观察,返回一个新stream,新stream类型不变,即peek不改变流的元素,接受一个实现了 consumer 接口的类,新Stream每个元素被消费的时候都会执行给定的消费函数,若新stream没有被消费, 则peek中的消费函数不会执行;
parallel:生成一个并行流。
终端操作——返回处理结果,一个stream只能进行一次终端操作。
foreach:遍历操作,遍历stream;
collect:汇聚操作,可变汇聚,把Stream中的元素收集到一个结果容器中(比如Collection);
reduce:汇聚操作,返回一个汇聚结果;
allMatch:搜索操作,是不是Stream中的所有元素都满足给定的匹配条件;
anyMatch:搜索操作,Stream中是否存在任何一个元素满足匹配条件;
noneMatch:搜索操作,是不是Stream中的所有元素都不满足给定的匹配条件;
findFirst:搜索操作,返回Stream中的第一个元素,如果Stream为空,返回空Optional;
findAny:搜索操作,获取任一元素,Optional容器只存1个或0个元素,遍历集合,获取到一个元素就结束遍历;
max:计算操作,取最大值,计算数值流的最大值,返回一个Optional的子类。
person类
class Person {
private String name;
private int type;
public Person() {}
public Person(String name, int type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Person person = (Person) o;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", type=" + type + '}';
}
public boolean isStudent() {
return this.type == 1;
}
public Person compareTo(Person person) {
return person.getType() > this.type ? person : this;
}
}
3、获取流
原始流(数值流)的获取
// 原始流的初始化
IntStream intStream = IntStream.of(1, 2, 3, 4, 5, 0, 8, 6, 8, 9, 7);
// 初始化0-10的整数流,包括10
IntStream intStream1 = IntStream.rangeClosed(0, 10);
intStream1.forEach(System.out::print);
IntStream intStream2 = IntStream.range(0, 10);
System.out.println();
intStream2.forEach(System.out::print);
// 原始类型流封装为流对象,数据量比较大的情况下,将基本数据类型(int,double...)包装成相应对象流的做法是低效的,因此可以初始化为原始流
Stream<Integer> stream = intStream.boxed();
DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);
LongStream longStream = LongStream.of(1, 2, 3, 4);
Stream.iterate(0, x -> x + 1).limit(10).parallel();
//对象流转数值流
Stream<Integer> stream1 = Arrays.asList(1,2,3).stream();
IntStream iStreaam = stream1.mapToInt(i -> i);
// 数组转流
Integer[] arr = {1, 2, 3};
Stream<Integer> stream3 = Arrays.stream(arr);
//迭代器转化成stream
Iterator<Integer> values = Arrays.asList(1, 2, 3).iterator();
Stream<Interger> iterStream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(values, Spliterator.SORTED), true);
Iterable<Integer> iterable = () -> values;
iterStream = StreamSupport.stream(iterable.spliterator(), false);
从流中获得集合,
Person[] ps = list.stream().toArray(Person[]::new);
String[] names = list.stream().map(Person::getName).toArray(String[]::new);
List<Person> personList = list.stream().collect(toList());
List<String> stringList = list.stream().map(Person::getName).collect(toList());
Set<Person> personSet = list.stream().collect(toSet());
Set<Integer> integerSet = list.stream().collect(mapping(Person::getType, toSet()));
HashSet<Person> personHashSet = list.stream().collect(toCollection(HashSet::new));
// list转map,如果有key相同,需要加第三个参数,设置重复key对应的value的处理,这里后面的覆盖前面的
Map<Integer, String> hashMap =
list.stream().collect(toMap(Person::getType, Person::getName, (x, y) -> y));
hashMap.forEach((k, v) -> System.out.println(k + "-" + v));
// groupingBy根据指定属性分组
Map<String, List<Person>> map = list.stream().collect(groupingBy(Person::getName));
map.forEach((k, v) -> System.out.println(k + "-" + v));
这里toList()使用了静态引用,可以直接使用Collectors下的静态方法。
import static java.util.stream.Collectors.*;
统计,combine 操作将一个IntSummaryStatistics和另一个IntSummaryStatistics组合起来
// 统计
IntSummaryStatistics intSummaryStatistics =
list.stream().collect(summarizingInt(Person::getType));
System.out.println("平均:" + intSummaryStatistics.getAverage());
System.out.println("记录数:" + intSummaryStatistics.getCount());
System.out.println("最大:" + intSummaryStatistics.getMax());
System.out.println("最小:" + intSummaryStatistics.getMin());
System.out.println("和:" + intSummaryStatistics.getSum());
IntSummaryStatistics intSummaryStatistics1 =
Stream.of(1, 2, 3, 3, 4, 5, 6).collect(summarizingInt(Integer::intValue));
// combine 操作将一个IntSummaryStatistics和另一个IntSummaryStatistics组合起来
intSummaryStatistics.combine(intSummaryStatistics1);
System.out.println(intSummaryStatistics.getSum());
filter操作,filter函数接收一个Lambda表达式作为参数,该表达式返回boolean。
// filter函数接收一个Lambda表达式作为参数,该表达式返回boolean。过滤流
List<Person> l = list.stream().filter(Person::isStudent).collect(toList());
List<Person> ll = list.stream().filter(p -> p.isStudent()).collect(toList());
map转换,将一个流转换成另一种类型的流,
// map映射对流中的每个元素执行一个函数,使得元素转换成另一种类型输出.转换流
List<String> ps = list.stream().map(Person::getName).collect(toList());
list.stream().map(p -> p.getType()).sorted();
distinct、limit、ship 去重、截取和跳过
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3);
// distinct去重
Object[] os = stream.distinct().collect(toList()).toArray();
Stream.of(os).forEach(s -> System.out.print(s));
System.out.println();
// collect为终端操作,stream只能执行一个终端操作,执行完后关闭
// List<Integer> list = stream.limit(5).collect(toList());
// limit截取流的前N个元素
Stream.of(os).limit(5).forEach(s -> System.out.print(s));
System.out.println();
// skip跳过流的前n个元素
Stream.of(os).skip(5).forEach(s -> System.out.print(s));
System.out.println();
// 创建无限流,通过limit提取指定大小
Stream.generate(() -> new Random().nextInt()).limit(10).forEach(System.out::println);
// 产生规律的数据,0为初始值
Stream.iterate(0, x -> x + 1).limit(10).forEach(System.out::println);
Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);
flatMap合并操作,将小流合并成一个大流,string.split(" ")将list分成三个stream,flatMap再将其合并成一个stream
List<String> list = new ArrayList();
list.add("I am a boy");
list.add("I love the girl");
list.add("But the girl loves another girl");
// 大流里面包含了一个个小流,将这些小流合并成一个流。split ""和" "不一样。flatMap拆解流
List<String> ll =
list.stream().map(string -> string.split(" ")).flatMap(Arrays::stream).collect(toList());
System.out.println(ll.size());
ll.stream().forEach(str -> System.out.print(str));
peek,观察strean中元素的状态,不改变元素
//返回一个新stream,新stream没有被消费,不执行打印语句
Stream<Person> s = list.stream().peek(System.out::println);
list.stream().peek(System.out::println).count();
// stream的转换操作都是lazy的,只在终端操作时循环stream,对每个元素执行中间操作和终端操作,这里包括peek,foreach
list.stream().peek(person -> System.out.println(person.getName())).forEach(System.out::println);
查看stream中元素的操作过程
public class PeekStream {
public static void main(String[] args) {
Stream<Integer> stream = Stream.iterate(0, x -> x + 1).limit(10);
//new PeekStream().testPeek(stream);
new PeekStream().testPeek(stream.parallel());
}
public void testPeek(Stream<Integer> stream) {
//peek
stream.peek(this::peek1).filter(x -> x > 5).peek(this::peek2).filter(x -> x < 8)
.peek(this::peek3).forEach(System.out::println);
}
public void peek1(int x) {
System.out.println(Thread.currentThread().getName() + ":->peek1->" + x);
}
public void peek2(int x) {
System.out.println(Thread.currentThread().getName() + ":->peek2->" + x);
}
public void peek3(int x) {
System.out.println(Thread.currentThread().getName() + ":->peek3->" + x);
}
}
sorted排序操作
// 按type从小到大排序
list.stream().sorted((p1, p2) -> {
if (p1.getType() < p2.getType()) {
return -1;
} else if (p1.getType() > p2.getType()) {
return 1;
} else {
return 0;
}
}).forEach(System.out::println);
// 按type的自然顺序排序
list.stream().sorted(Comparator.comparing(Person::getType)).forEach(System.out::println);
// 按type的自然顺序倒序排序
list.stream().sorted(Comparator.comparing(Person::getType).reversed())
.forEach(System.out::println);
String[] ss = {"sad", "aer", "fdsd", "her"};
// 自然排序比较器
Stream.of(ss).sorted(Comparator.naturalOrder()).forEach(System.out::println);
// 逆自然排序比较器
Stream.of(ss).sorted(Comparator.reverseOrder()).forEach(System.out::println);
搜索操作
// anyMatch是否匹配任一元素
boolean result = list.stream().anyMatch(Person::isStudent);
System.out.println("是否包含学生:" + result);
// allMatch是否匹配所有元素
boolean result1 = list.stream().allMatch(Person::isStudent);
System.out.println("是否全部是学生:" + result1);
// noneMatch是否没有一个匹配
boolean result2 = list.stream().noneMatch(Person::isStudent);
System.out.println("是否全部不是学生:" + result2);
String str = "";
// findAny获取任一元素,Optional容器只存1个或0个元素
Optional<Person> person3 = list.stream().findAny();
// parallel并行流
Optional<Person> person4 = list.stream().parallel().findAny();
// findFirst获取流的第一个元素
Optional<Person> person5 = list.stream().findFirst();
System.out.println("有序流抽取一个人:" + person3.get());
System.out.println("随机抽取一个人:" + person4.get());
System.out.println("抽取第一个人:" + person5.get());
Optional<Person> optional = list.stream().parallel().filter(Person::isStudent).findAny();
optional.ifPresent(System.out::println);
// System.out.println("max:" + list.stream().max((p1, p2) -> p1.compareTo(p2)));
reduce聚合操作
// reduce聚合操作,求和,最后返回sum,最开始,sum是流第一个元素的值,num是流第二个元素的值,返回Optional对象,因为stream可能为空
System.out.println(list.stream().map(Person::getType).reduce((sum, num) -> sum + num));
// 第一个参数设置初始值,返回String
System.out.println(list.stream().map(Person::getName).reduce("", (str, s) -> str + s));