1、概念
Stream API提供了一种高效的且易于使用的处理数据方法
Stream(流),是数据渠道,用于操作数据源(集合、数组等)所产生的元素序列
所以流代表了计算
注意:
⑴ Stream自己不会存储元素
⑵ Stream不会改变源对象,会返回一个新的带有结果的Stream
⑶ Stream操作是延迟执行的,也就是会等到需要结果的时候才会执行
2、Stream的操作
⑴ 创建Stream
通过集合或数组来获取一个流
⒈ Arrays的stream方法
public static <T> Stream<T> stream(T[] array) {
return stream(array, 0, array.length);
}
⒉ Collection接口的stream方法
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
获取一个串行流
⒊ Stream的of方法
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
传递一个数组
public static<T> Stream<T> of(T t) {
return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}
传递一个对象
⒋ Stream的iterate方法
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}
创建一个无限流,第一个参数是种子数,第二个参数是函数式接口
种子数即要生成的元素的起始元素
函数式接口则定义了元素生成的策略
⒌ Stream的generate方法
public static<T> Stream<T> generate(Supplier<T> s) {}
创建一个无限流,需要提供一个供给型函数
⒍ 示例
String[] array = {"a", "b", "c", "d"};
List<Integer> list = new ArrayList<Integer>() {
{
add(1);
add(2);
add(3);
add(4);
}
};
Stream<String> streamArray = Arrays.stream(array);
Stream<Integer> streamList = list.stream(); // 串行流
streamList = list.parallelStream(); // 并行流
Stream<Double> stream = Stream.of(1D, 2D, 3D, 4D);
stream = Stream.of(10D);
Stream<Integer> stream = Stream.iterate(1, (x) -> {return ++x;}); // 无限流
stream.limit(10)
.forEach(System.out::println);
stream.close(); // 关闭流
Stream<Integer> stream = Stream.generate(() -> {return (int) (Math.random() * 10 + 1);}); // 创建1-10的随机数
stream.limit(10)
.forEach(System.out::println);
stream.close();
⑵ 中间操作
一个中间操作链,对数据源的数据进行操作
⒈ 筛选和切片
filter
Stream<T> filter(Predicate<? super T> predicate);
筛选,需要传递一个断言型接口
distinct
Stream<T> distinct();
去重。注意:这里会调用元素的hashCode和equals方法
limit
Stream<T> limit(long maxSize);
取出前几个元素。如果元素个数不够,则有几个就返回几个
skip
Stream<T> skip(long n);
跳过前几个元素。如果跳过后,元素的个数为0,则返回一个包含了空元素的Stream
示例
【bean对象】
public class Person {
private String name;
private Integer age;
private Double salary;
/** Constructor & Getter & Setter */
}
List<Person> list = new ArrayList<Person>() {
{
add(new Person("张三", 14, 2000.15D));
add(new Person("李四", 16, 3010.5D));
add(new Person("王五", 13, 2600.43D));
add(new Person("赵六", 11, 2800.43D));
add(new Person("王五", 13, 2600.43D));
add(new Person("田七", 14, 2758.54D));
}
};
list.stream()
.filter((person) -> {return 12 < person.getAge();}) // 筛选年龄大于12岁的
.distinct() // 去重
.skip(1) // 跳过第一个元素
.limit(3) // 取出前3个元素
.forEach(System.out::println);
⒉ 映射
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
映射规则,需要传递一个供给型函数
示例
List<Person> list = Arrays.asList(
new Person("张三", 14, 2000.15D),
new Person("李四", 16, 3010.5D),
new Person("王五", 13, 2600.43D),
new Person("赵六", 11, 2800.43D),
new Person("王五", 13, 2600.43D),
new Person("田七", 14, 2758.54D)
);
List<String> names = list.stream()
.map(Person::getName)
.collect(Collectors.toList());
names.forEach(System.out::println);
mapToDouble
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
示例
OptionalDouble optionalDouble = list.stream().mapToDouble(Person::getSalary).max();
System.out.println(optionalDouble.getAsDouble());
mapToInt
mapToLong
flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
传递一个函数型的接口,返回值类型为一个Stream流
示例
List<String> names = Arrays.asList("ada", "bob", "cad", "dgb");
names.stream()
.flatMap(类名::mapper) // 静态方法引用
.sorted() // 自然排序
.forEach(System.out::print);
【需要自定义一个方法】
private static Stream<Character> mapper(String str) {
List<Character> temp = new ArrayList<Character>();
char[] array = str.toCharArray();
for (int i = 0, len = array.length; i < len; i++) {
temp.add(array[i]);
}
return temp.stream();
}
⒊ 排序
sorted
Stream<T> sorted();
自然排序
public final Stream<P_OUT> sorted(Comparator<? super P_OUT> comparator) {}
定制排序,需要传递一个Comparator比较器
示例
【自然排序】
List<Integer> list = Arrays.asList(1, 2, 34, 5, 53, 5, 45, 35);
list.stream()
.sorted()
.forEach(System.out::println);
【定制排序】
list.stream()
.sorted((x, y) -> {return -(x.compareTo(y));}) // 倒序
.forEach(System.out::println);
⑶ 终止操作
Stream流水线的最终生成结果,其结果可能不是Stream,可能是集合,也可能是void
⒈ 查找与匹配
allMatch
boolean allMatch(Predicate<? super T> predicate);
全部元素匹配,需要传递一个断言型函数
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
boolean flag = list.stream()
.allMatch((i) -> {return 10 > i;});
System.out.println(flag);
anyMatch
boolean anyMatch(Predicate<? super T> predicate);
任意元素匹配,需要传递一个断言型函数
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
boolean flag = list.stream()
.anyMatch((i) -> {return 5 >= i;});
System.out.println(flag);
noneMatch
boolean noneMatch(Predicate<? super T> predicate);
没有元素匹配,需要传递一个断言型函数
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
boolean flag = list.stream()
.noneMatch((i) -> {return 5 < i;});
System.out.println(flag);
findFirst
Optional<T> findFirst();
取出第一个元素,并将元素封装到Optional对象中,返回
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> optional = list.stream()
.findFirst();
System.out.println(optional.get());
findAny
Optional<T> findAny();
取出任意一个元素(符合条件的第一个),并将元素封装到Optional对象中,返回
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> optional = list.stream()
.filter((x) -> {return 4 < x;}) // 过滤大于4的元素
.findAny(); // 等同于取出第一个大于4的元素
System.out.println(optional.get());
count
long count();
返回Stream中包含的元素的个数
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
long count = list.stream()
.count();
System.out.println(count);
max
Optional<T> max(Comparator<? super T> comparator);
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = list.stream()
.max(Integer::compareTo); // 实例方法引用
System.out.println(max.get());
min
Optional<T> min(Comparator<? super T> comparator);
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = list.stream()
.min(Integer::compareTo);
System.out.println(max.get());
forEach
void forEach(Consumer<? super T> action);
内部遍历,需要传递一个消费型接口
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream()
.forEach(System.out::println);
⒉ 规约
reduce
T reduce(T identity, BinaryOperator<T> accumulator);
第一个参数传递结果的起始值,第二个参数需要传递一个BiFunction<T,T,T>类型的函数式接口。返回第一个参数类型的返回值
interface BinaryOperator<T> extends BiFunction<T,T,T> {}
Optional<T> reduce(BinaryOperator<T> accumulator);
需要传递一个BiFunction<T,T,T>类型的函数式接口,将结果封装到Optional中并返回
示例
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> optional = list.stream()
.reduce(Integer::sum);
System.out.println(optional.get());
Integer sum = list.stream()
.reduce(0, (x, y) -> {return x + y;}); // 结果的起始值为0
System.out.println(sum);
⒊ 收集
collect
<R, A> R collect(Collector<? super T, A, R> collector);
需要传递Collector的实现类Collectors
toList
public static <T> Collector<T, ?, List<T>> toList() {}
将流中的元素收集到List集合(ArrayList)中
toSet
public static <T> Collector<T, ?, Set<T>> toSet() {}
将流中的元素收集到Set集合(HashSet)中
toCollection
public static <T, C extends Collection<T>>
Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {}
把流中的元素收集到Collection集合中。需要传递集合的类型,可以使用构造引用
示例
List<Integer> list = Arrays.asList(1, 3, 2, 3, 5, 4, 5);
Collection<Integer> collection = list.stream()
.collect(Collectors.toCollection(LinkedList::new)); // 创建的集合类型为LinkedList
System.out.println(collection);
counting
public static <T> Collector<T, ?, Long> counting() {}
统计元素个数,返回值类型为Long
示例
List<Integer> list = Arrays.asList(1, 3, 2, 3, 5, 4, 5);
Long count = list.stream()
.collect(Collectors.counting());
System.out.println(count); // 7
summingInt
public static <T> Collector<T, ?, Integer>
summingInt(ToIntFunction<? super T> mapper) {}
对元素的整数属性进行合计。需要传递ToIntFunction类型的函数式接口,该函数用以定义如何合计元素的值
示例
List<Person> persons = new ArrayList<Person>(3);
persons.add(new Person(12));
persons.add(new Person(13));
persons.add(new Person(15));
Integer sum = persons.stream()
.collect(Collectors.summingInt(Person::getAge)); // 实例方法引用
System.out.println(sum);
averagingInt
public static <T> Collector<T, ?, Double>
averagingInt(ToIntFunction<? super T> mapper) {}
计算Integer元素的平均值。需要传递ToIntFunction类型的函数式接口
示例:
List<Person> persons = new ArrayList<Person>(3);
persons.add(new Person(12));
persons.add(new Person(13));
persons.add(new Person(15));
Double avgAge = persons.stream()
.collect(Collectors.averagingInt(Person::getAge));
System.out.println(avgAge);
summarizingInt
public static <T>
Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {}
获取处理指定元素类型的收集器
IntSummaryStatistics类的方法:
double getAverage()
long getCount()
int getMax()
int getMin()
long getSum()
示例:
List<Person> persons = new ArrayList<Person>(3);
persons.add(new Person(12));
persons.add(new Person(13));
persons.add(new Person(15));
IntSummaryStatistics intSummaryStatistics = persons.stream().collect(Collectors.summarizingInt(Person::getAge));
double avg = intSummaryStatistics.getAverage(); // 平均值
long count = intSummaryStatistics.getCount(); // 统计个数
int max = intSummaryStatistics.getMax(); // 最大值
int min = intSummaryStatistics.getMin(); // 最小值
long sum = intSummaryStatistics.getSum(); // 合计
System.out.println(avg);
System.out.println(count);
System.out.println(max);
System.out.println(min);
System.out.println(sum);
joining
public static Collector<CharSequence, ?, String> joining() {}
拼接元素为字符串
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {}
传递分割符号
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {}
传递分割符号,前缀和后缀
示例:
List<Person> persons = new ArrayList<Person>(3);
persons.add(new Person("张三"));
persons.add(new Person("李四"));
persons.add(new Person("王五"));
String result = persons.stream()
.map(Person::getName)
.collect(Collectors.joining());
System.out.println(result);
result = persons.stream()
.map(Person::getName)
.collect(Collectors.joining(", "));
System.out.println(result);
result = persons.stream()
.map(Person::getName)
.collect(Collectors.joining(",", "[", "]"));
System.out.println(result);
maxBy
public static <T> Collector<T, ?, Optional<T>>
maxBy(Comparator<? super T> comparator) {}
根据比较器选择最大值
示例:
List<Person> persons = new ArrayList<Person>(3);
persons.add(new Person("ada",14));
persons.add(new Person("bob", 12));
persons.add(new Person("cad",15));
Optional<Integer> optional = persons.stream()
.map(Person::getAge)
.collect(Collectors.maxBy(Integer::compareTo));
System.out.println(optional.get());
minBy
根据比较器选择最小值
reducing
public static <T> Collector<T, ?, T>
reducing(T identity, BinaryOperator<T> op) {}
从一个指定的值开始,将各个元素按照指定的规则计算到一起
示例:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
Integer sum = list.stream()
.collect(Collectors.reducing(0, Integer::sum));
System.out.println(sum);
groupingBy
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) {}
按照指定的属性对元素进行分组操作,返回Map<属性,List<对应属性值的集合>>
示例:
List<Person> list = Arrays.asList(
new Person(13),
new Person(23),
new Person(23),
new Person(14)
);
Map<Integer, List<Person>> map = list.stream()
.collect(Collectors.groupingBy(Person::getAge));
map.forEach((k, v) -> {System.out.println(k + "-" + v);});
partitioningBy
public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {}
按照true | false进行分区
示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> collect = numbers.stream()
.collect(Collectors.partitioningBy((i) -> {return 3 < i;}));
collect.forEach((k, v) -> {System.out.println(k + ":" + v);});
3、Fork/Join框架
⑴ 概念
将一个大任务拆分(fork)成多个小任务,知道不能再拆分为止(达到临界值),然后再将一个一个小任务的结果汇总(join)起来
⑵ 与线程池的区别
Fork/Join采用工作窃取模式(work-stealing),即当执行新任务时,会把任务拆分成更小的任务去执行,再将小任务添加到线程队列中,然后再随机从一个线程队列中偷取一个小任务,并把它放到自己的线程队列中
Fork/Join的优势体现在对任务的处理方式上
一般的线程池,如果其中一个线程的执行任务无法继续进行,则该线程会处于等待状态
而在Fork/Join框架中,由于该线程处于空闲状态,所以它会偷取其他线程队列上的尚未被执行的子任务,并处理,以此提高了效率
⑶ API
编写一个类,并继承RecursiveTask抽象类,并实现compute方法
public final ForkJoinTask fork() {}
拆分任务
public final V join() {}
合并任务
⑷ 示例
/**
* 求和
*/
public class TestForkJoin extends RecursiveTask<Long> {
private static final long THRESHOLD = 1000L;
private long start;
private long end;
public TestForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start; // 计算出间距
if (THRESHOLD >= length) {
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2; // 求出临界值
TestForkJoin left = new TestForkJoin(start, middle);
left.fork(); // 拆分任务,添加到线程队列中
TestForkJoin right = new TestForkJoin(middle + 1, end); // 从中间部分加1开始计算
right.fork();
return left.join() + right.join(); // 合并子任务的结果
}
}
}
4、并行流和串行流
⑴ 概念
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流(Stream)
⑵ API
IntStream
LongStream
DoubleStream
S parallel();
获取并行流
S sequential();
获取串行流
public static IntStream rangeClosed(int startInclusive, int endInclusive) {
if (startInclusive > endInclusive) {
return empty();
}
获取从开始到结束的自增结果,每次自增1
类似于:
for (int i = startInclusive; i <= endInclusive ; i++) { ... }
注意:如果第一个参数(开始位置)大于第二个参数(结束位置),则返回空的Stream
public static LongStream rangeClosed(long startInclusive, final long endInclusive) {
if (startInclusive > endInclusive) {
return empty();
}
获取从开始到结束的自增结果,每次自增1
类似于:
for (long i = startInclusive; i <= endInclusive ; i++) { ... }
注意:如果第一个参数(开始位置)大于第二个参数(结束位置),则返回空的Stream
注意:DoubleStream没有rangeClosed方法
⑶ 示例
long sum = LongStream.rangeClosed(1L, 100000000L)
.sequential()
.sum();
System.out.println(sum);