1. Stream 的运用

Stream 是什么?

Stream 是数据途径,用于操作数据源(数组、调集等)所生成的元素序列。

Java8两大最为重要的改动便是 Lambda表达式Stream API,这两种改动的引入带来的是新的笼统办法 (函数式编程),面向对象编程是对数据进行笼统,而函数式编程是对行为进行笼统

Stream 是 Java8 中处理调集的要害笼统概念,能够指定对调集进行的操作,能够履行杂乱的查找、过滤、映射数据等操作,Stream API 提供了一种高效且易于运用的处理数据的办法。


四个有必要要知道的内置函数接口

  1. 消费型接口: Consumer<T> void accept(T t) 有参数,无回来值的笼统办法;
  2. 供应型接口: Supplier <T> T get() 无参有回来值的笼统办法;
  3. 判定型接口: Predicate<T> boolean test(T t) 有参,但是回来值类型是固定的boolean;
  4. 函数型接口: Function<T,R> R apply(T t) 有参有回来值的笼统办法;
// 消费接口界说
Consumer<Student> greeter = (p) -> System.out.println("Hello, " + p.firstName);
// 消费
greeter.accept(new Student("Luke", "Skywalker"));
// 供应接口界说
Supplier<Student> supplier = Student::new;
// 供应
supplier.get();
// 判定型接口界说
Predicate<String> predicate = (s) -> s.length() > 0;
// 判定
predicate.test("s");              // true
predicate.test("");     // false
// 函数型接口界说
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
// 运用
backToString.apply("123");     // "123"

Java基础之Stream的使用


Stream 的运用分为三个过程

  1. 创立Stream (运用数据源能够是调集、数组来获取流)
  2. 中心操作 (对数据源的数据进行处理)
  3. 停止操作 (先履行中心操作发生成果后停止流,之后不能再运用该流)

Java基础之Stream的使用

惰性求值

中心操作不会履行任何的处理,而是在停止操作时一次性全部处理,这便是惰性求值

// 像这样的代码并未做什么实际工作
lists.stream().filter(x -> x != 1)
// 像这种有停止操作的代码才会发生新值
List<Integer> list1 = list.parallelStream().filter(x -> x != 1).collect(Collectors.toList());

1.1 创立 Stream 的办法

调集创立

  1. 次序流:运用次序办法遍历,每个item读完之后再读下一个item
  2. 并行流:运用并行遍历,将数据分为多个段,各个段的数据都在不同线程下处理

在多核计算机的情况下理论上并行流会比次序流快上一倍左右

① 次序履行:default Stream<E> stream() 回来一个次序流

// 将list列表经过stream()生一个流过滤1最终打印
List<Integer> list1 = list.stream().filter(x -> x != 1).collect(Collectors.toList());

② 并行履行:default Stream<E> parallelStream() 回来一个并行流

List<Integer> list1 = list.parallelStream().filter(x -> x != 1).collect(Collectors.toList());

数组创立

经过Arrays静态办法获取数组流:static <T> Stream<T> stream(T[] array)

// 将array数组经过Arrays的静态办法生一个流过滤1最终打印
Arrays.stream(array).filter(x -> x != 1).forEach(System.out::println);

Stream创立

经过调用Stream类的静态办法创立流 (留意后两个生成的是无限流)

① 经过显现值:public static<T> Stream<T> of(T... values)

// 经过显现值1,2,3,4生成一个流过滤掉1最终打印
Stream.of(1,2,3,4).filter(x -> x != 1).forEach(System.out::println);

② 经过迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)

// 从0开端迭代每次加1生成一个无限流经过limit约束前十位最终打印
Stream.iterate(0, x -> x + 1).limit(10).forEach(System.out::println);

③ 经过生成:public static<T> Stream<T> generate(Supplier<T> s)

// 经过Math的随机数函数生成一个无限流经过limit约束前五位最终打印
Stream.generate(Math::random).limit(5).forEach(System.out::println);

1.2 中心操作

Stream<T> filter(Predicate<? super T> predicate);

接纳Lambda,从流中排除某些元素;

List<Integer> list = Arrays.asList(1,2,3,4);
// filter中传入一个判定型接口Predicate过滤掉遍历这个调集是回来false的成果
List<Integer> list1 = list.stream().filter(x -> x != 1).collect(Collectors.toList());
list1.forEach(System.out::print); // 234

Stream<T> distinct();

筛选,经过流所生成元素的 hashCode() 和 equals() 去除重复元素;

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 去重
nums.stream().distinct().forEach(System.out::print); // 1234

Stream<T> limit(long maxSize);

截断流,使其元素不超越给定数量

// 经过Math的随机数函数生成一个无限流经过limit约束前五位最终打印
Stream.generate(Math::random).limit(5).forEach(System.out::println);

Stream<T> skip(long n);

越过元素,回来一个扔掉了前 n 个元素的流。若流中元素缺乏 n 个,则回来一个空流。与 limit(n) 互补

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 去重
nums.stream().skip(2).forEach(System.out::print); // 234

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

接纳一个函数作为参数,该函数会被运用到每个元素上,并将其映射成一个新的元素。

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 经过map对每个元素进行类型转换
List<Long> collect = nums.stream().map(Long::valueOf).collect(Collectors.toList());

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

接纳一个函数作为参数,将流中的每个值都换成另一个流,然后把一切流连接成一个流

// 合并多个流
List<Integer> result= Stream.of(Arrays.asList(1,3),Arrays.asList(5,6)).flatMap(Collection::stream).collect(Collectors.toList());

Stream<T> sorted();

发生一个新流,其间按天然次序排序

List<Integer> nums = Arrays.asList(8,6,7,3);
// 天然排序
nums.stream().sorted().forEach(System.out::print); // 3678

Stream<T> sorted(Comparator<? super T> comparator);

发生一个新流,其间按比较器次序排序

List<Integer> nums = Arrays.asList(8,6,7,3);
// 比较器排序
nums.stream().sorted((x,y) -> (y-x)).forEach(System.out::print); // 8763

1.3 停止操作

boolean allMatch(Predicate<? super T> predicate);

查看是否匹配一切元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 查看是否调集里边的元素都等于1
System.out.println(nums.stream().allMatch(x -> x == 1)); // false

boolean anyMatch(Predicate<? super T> predicate);

查看是否至少匹配一个元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 查看是否调集里边的元素有等于1的
System.out.println(nums.stream().anyMatch(x -> x == 1)); // true

boolean noneMatch(Predicate<? super T> predicate);

查看是否没有匹配一切元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 查看是否调集里边的元素都不等于1
System.out.println(nums.stream().noneMatch(x -> x == 1)); // false

Optional<T> findFirst();

回来第一个元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 拿到调集第一个元素用Optional存储能够经过get取出来
System.out.println(nums.stream().findFirst()); // Optional[1]
System.out.println(nums.stream().findFirst()); // 1

Optional<T> findAny();

回来当前流中的恣意元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 拿到调集恣意元素用Optional存储能够经过get取出来
System.out.println(nums.stream().findFirst()); // Optional[1]
System.out.println(nums.stream().findFirst()); // 1

long count();

回来流中元素总数

List<Integer> nums = Arrays.asList(3,7,3);
// 调集巨细
System.out.println(nums.stream().count()); // 3

Optional<T> max(Comparator<? super T> comparator);

回来流中最大值

List<Integer> nums = Arrays.asList(3,7,3);
// 回来比较器下的最大值用Optional存储经过get取出(留意这儿的比较器是从大到小排序)
System.out.println(nums.stream().max((x, y) -> (y - x)).get()); // 3

Optional<T> min(Comparator<? super T> comparator);

回来流中最小值

List<Integer> nums = Arrays.asList(3,7,3);
// 回来比较器下的最小值用Optional存储经过get取出(留意这儿的比较器是从大到小排序)
System.out.println(nums.stream().min((x, y) -> (y - x)).get()); // 7

void forEach(Consumer<? super T> action);

内部迭代(运用 Collection 接口需求用户去做迭代,称为外部迭代。相反,Stream API 运用内部迭代)

List<Integer> nums = Arrays.asList(3,7,3);
// 内部迭代
nums.stream().forEach(System.out::print); // 373

Optional<T> reduce(BinaryOperator<T> accumulator);

能够将流中元素重复结合起来,得到一个值。回来 T

List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
// 将调集的值变成double类型并抹个零经过reduce重复结合即相加得到总和
double bill = costBeforeTax.stream().map((cost) -> 0.1 * cost).reduce(Double::sum).get();
System.out.println(bill); // 150.0

T reduce(T identity, BinaryOperator<T> accumulator);

能够将流中元素重复结合起来,得到一个值。回来 Optional<T>

double bill = 100.0;
List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
// 跟上面的比便是多一个初始值在重复结合
bill = costBeforeTax.stream().map((cost) -> 0.1 * cost).reduce(bill, Double::sum);
System.out.println(bill); // 250.0

<R, A> R collect(Collector<? super T, A, R> collector);

将流通换为其他形式。接纳一个Collector接口的实现,用于给Stream中元素做汇总的办法

Java基础之Stream的使用

Java基础之Stream的使用