Java流操作

文章目录

一、Java流

一、Java流

1.Java流 - Java流操作

外部迭代

当使用Java集合时,我们使用外部迭代。

在外部迭代中,我们为每个循环使用for或,或者为序列中的集合的集合和过程元素获取迭代器。

以下代码计算列表中所有奇整数的平方和。

它使用每个循环访问列表中的每一个元素,然后使用if语句来过滤奇整数。

之后,它计算平方,最后存储平方和与和变量。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = 0;
    for (int n : numbers) {
      if (n % 2 == 1) {
        int square = n * n;
        sum = sum + square;
      }
    }
    System.out.println(sum);
  }
}

上面的代码生成以下结果。

img

内部迭代

我们可以使用stream重写上面的代码。 它做的完全一样。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
        .filter(n -> n % 2  == 1) //进行奇数过滤
        .map(n  -> n * n) //进行相乘计算
        .reduce(0, Integer::sum);//进行相加计算

    System.out.println(sum);
  }
}

在上面的代码中,我们没有使用循环语句来遍历List。 我们通过流在内部执行循环。

对于奇整数计算,我们使用lambda表达式。 我们首先做了过滤,然后映射然后减少。

上面的代码生成以下结果。

img

顺序

外部迭代通常意味着顺序代码。顺序代码只能由一个线程执行。

流被设计为并行处理元素。

以下代码并行计算列表中奇整数的平方和。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.parallelStream()
        .filter(n -> n % 2  == 1)
        .map(n  -> n * n)
        .reduce(0, Integer::sum);

    System.out.println(sum);
  }
}

我们做的只是用parallelStream()替换stream()。

使用流提供的内部迭代时,并行计算很容易。

上面的代码生成以下结果。

img

命令式与功能式

在命令式编程中,我们不仅控制要做什么,还要如何做。

例如,当使用命令性编程来对列表中的整数求和时。 我们必须决定如何迭代列表中的每个元素。 我们可以使用for循环,for-each循环,或者我们可以从list中获取一个Iterator对象,并使用while循环。 然后我们也要做总和。

在声明性编程中,我们只需要告诉该做什么,该部分如何由系统本身处理。

集合支持命令式编程,而流支持声明式编程。

Streams API通过使用lambda表达式支持函数式编程。

我们要对流元素执行的操作通常通过传递lambda表达式完成。

流上的操作产生结果而不修改数据源。

中间业务终端业务

流支持两种类型的操作:

  • 中间操作
  • 终端操作

中间操作也称为惰性操作。

终端操作也称为急切操作。

惰性操作不处理元素,直到在流上调用热切操作。

流上的中间操作产生另一流。

Streams链接操作以创建流管道。

在下面的代码中filter()和map()都是惰性操作。 而reduce()是急切的操作。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.parallelStream()
        .filter(n -> n % 2  == 1)
        .map(n  -> n * n)
        .reduce(0, Integer::sum);

    System.out.println(sum);
  }
}

上面的代码生成以下结果。

img

2.Java流 - Java流API

流相关的接口和类在java.util.stream包中。

AutoCloseable接口来自java.lang包。

所有流接口从继承自AutoCloseable接口的BaseStream接口继承。

AutoCloseable
 |
 +--BaseStream
     |
     +--IntStream
     |
     +--LongStream
     |
     +--DoubleStream
     |
     +--Stream<T>

如果流使用集合作为其数据源,并且集合不需要关闭。

如果流基于可关闭的数据源(例如文件I/O通道),那么我们可以使用try-with-resources语句创建流,以使其自动关闭。

BaseStream

BaseStream接口定义所有类型的流的所有方法。

  • Iterator iterator()
    终端操作
    返回流的迭代器。
  • sequential()
    中间操作
    返回顺序流。 如果流已经是顺序的,则它返回自身。 它将并行流转换为顺序流。
  • parallel()
    中间操作
    返回并行流。 如果流已经是并行的,则它返回自身。 它将顺序流转换为并行流。
  • boolean isParallel()
    如果流是并行,则返回true,否则返回false。
    在调用终端流操作方法后调用此方法可能会产生不可预测的结果。
  • unordered()
    中间操作
    返回流的无序版本。 如果流已经是无序的,则它返回自身。

Stream<T> 接口表示元素类型T的流。

流 表示学生对象流。

Stream 接口包含诸如filter(),map(),reduce(),collect(),max(),min()等。

当使用原始类型时,我们可以使用三个专门的流接口,称为IntStream,LongStream和DoubleStream。

这些接口提供了处理原始值的方法。

对于其他基本类型,例如float,short,byte,我们仍然可以使用三个专用流接口。

在下面的代码中,我们将使用stream来计算列表中所有奇整数的平方和。

我们将使用以下步骤进行计算。

创建流

Collection接口中的stream()方法返回一个顺序流。 这样,集合充当数据源。

下面的代码创建一个List 并从列表中获取一个Stream

List<Integer>  numbersList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> numbersStream  = numbersList.stream();

过滤流

如果指定的谓词对于该元素返回真,Stream filter()使用Predicate来保留元素。

以下语句获取仅奇数整数的流:

Stream< Integer> oddNumbersStream = numbersStream.filter(n - > n%2 == 1);

映射流

Stream< T> map()使用一个Function来映射每个元素在流中创建新流。

以下语句将流映射到其正方形:

Stream<Integer> aStream = stream.map(n -> n * n);

Reduce流(累加器)

reduce(T identity,BinaryOperator<T>累加器)将流减少到单个值。

它采用一个初始值和一个BinaryOperator<T>作为参数的累加器。

reduce(T identity,BinaryOperator< T>累加器)使用所提供的初始值和关联累积函数对该流的元素执行减少,并返回减小的值。

这相当于:

T result = identity;
for (T element : this stream)
  result = accumulator.apply(result, element)
return result;

以下代码将流中的所有整数相加。

int sum = aStream.reduce(0, (n1, n2) -> n1 + n2);

Integer.sum()方法执行两个整数的和。

我们可以使用方法引用重写代码。

int sum = aStream.reduce(0, Integer::sum);

Together

以下代码将每个步骤链接在一起。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
        .filter(n -> n % 2  == 1)
        .map(n  -> n * n)
        .reduce(0, Integer::sum);

    System.out.println(sum);
  }
}

上面的代码生成以下结果。

img

有序流与无序流

流可以是有序的或无序的。

有序流保持其元素的顺序。

Streams API可以将有序流(其可以表示有序数据源,例如列表或有序集)转换成无序流。

我们还可以通过应用排序中间操作将无序流转换为有序流。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(3,7,9,3,1,2,1, 2, 3, 4, 5);
    numbers.stream()
        .filter(n -> n % 2  == 1)
        .sorted()
        .forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

3.Java 可选

Java 8引入了一个java.util.Optional类来优雅地处理NullPointerException。

Optional是可以包含或不包含非空值的非空值的包装器。

可能返回null的方法应返回Optional,而不是null。

如果其包含非空值,则来自可选的isPresent()返回true,否则返回false。

如果get()方法包含非空值,则返回非空值,否则抛出NoSuchElementException。

当一个方法返回一个可选,你必须检查它是否包含一个非空值,然后再询问它的值。

如果在确保它包含非空值之前调用了get()方法,则会抛出NoSuchElementException,而不是抛出NullPointerException。

Java流 - Java可选

Java 8引入了一个java.util.Optional类来优雅地处理NullPointerException。

Optional是可以包含或不包含非空值的非空值的包装器。

可能返回null的方法应返回Optional,而不是null。

如果其包含非空值,则来自可选的isPresent()返回true,否则返回false。

如果get()方法包含非空值,则返回非空值,否则抛出NoSuchElementException。

当一个方法返回一个可选,你必须检查它是否包含一个非空值,然后再询问它的值。

如果在确保它包含非空值之前调用了get()方法,则会抛出NoSuchElementException,而不是抛出NullPointerException。

创建可选对象(判空处理)

Optional 类提供了三个静态工厂方法来创建Optional对象。

  • 可选 empty()
    返回一个空的Optional。
    从此方法返回的可选不包含非空值。
  • (T值)的可选
    返回一个包含指定值作为非空值的Optional。
    如果指定的值为null,它会抛出NullPointerException。
  • 可选的T值(T值)
    如果值为非空,则返回包含指定值的Optional。
    如果指定的值为null,则返回一个空的Optional。

以下代码显示如何创建Optional对象:

import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    Optional<String> empty  = Optional.empty();
    System.out.println(empty);

    Optional<String> str = Optional.of("www.w3cschool.cn");
    System.out.println(str);

    String nullableString = ""; 
    Optional<String> str2  = Optional.of(nullableString);
    System.out.println(str2);
  }
}

上面的代码生成以下结果。

img

如果包含非空值,以下代码将在可选中打印值:

import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    Optional<String> str = Optional.of("www.w3cschool.cn");

    if (str.isPresent()) {
      String value = str.get();
      System.out.println("Optional contains " + value);
    } else {
      System.out.println("Optional is  empty.");
    }
  }
}

上面的代码生成以下结果。

img

可选ifPresent

if Present(Consumer<? super T> action)方法对Optional中包含的值执行操作。

如果Optional是空的,这个方法不做任何事情。

以下代码打印出来自Optional的内容。

import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    Optional<String> str = Optional.of("www.w3cschool.cn");

    str.ifPresent(value -> System.out.println("Optional contains " + value));
  }
}

上面的代码生成以下结果。

img

如果Optional是空的,代码将不会打印任何东西。

可选值

以下是获取可选值的四个方法:

  • T get()
    返回Optional中包含的值。如果Optional是空的,它会抛出一个NoSuchElementException异常。
  • T orElse(T defaultValue)
    返回Optional中包含的值。
    如果Optional为空,它返回指定的defaultValue。
  • T orElseGet(Supplier<? extends T> defaultSupplier)
    返回Optional中包含的值。
    如果Optional为空,则返回从指定的defaultSupplier返回的值。
  • T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable
    返回Optional中包含的值。
    如果Optional为空,它将抛出从指定的exceptionSupplier返回的异常。

OptionalInt,OptionalLong和OptionalDouble处理可选的基本值。

  • OptionalInt类中的getAsInt()方法返回int值。
  • getAsLong()方法从OptionalLong类返回long值。
  • getAsDouble()方法从OptionalDouble类返回double值。

基本可选类的getters当它们为空时也会抛出NoSuchElementException。

以下代码显示了如何使用OptionalInt类:

import java.util.OptionalInt;

public class Main {
  public static void main(String[] args) {
    OptionalInt number = OptionalInt.of(2);

    if (number.isPresent()) {
      int value = number.getAsInt();
      System.out.println("Number is " + value);
    } else {
      System.out.println("Number is absent.");
    }
  }
}

上面的代码生成以下结果。

img

流可选值

一些流操作返回可选。 例如,所有流类中的max()方法返回一个可选对象。 当对空流使用max()方法时,返回值是一个没有内容的可选对象。

通过使用可选类,我们可以优雅地处理这些方法的返回值。

以下代码显示了如何使用返回的max()形式的Optional对象。

import java.util.OptionalInt;
import java.util.stream.IntStream;

public class Main {
  public static void main(String[] args) {

    OptionalInt maxOdd = IntStream.of(10, 20, 30).filter(n -> n % 2 == 1).max();
    if (maxOdd.isPresent()) {
      int value = maxOdd.getAsInt();
      System.out.println("Maximum odd  integer is " + value);
    } else {
      System.out.println("Stream is  empty.");
    }
  }
}

二、Java流创建

1.Java流 - Java创建流

已将新方法添加到Java库以返回流。

我们可以通过以下方式创建流。

  • 从值创建流
  • 从空流创建流
  • 从函数创建流
  • 从数组创建流
  • 从集合创建流
  • 从文件创建流
  • 从其他来源创建流

在以下部分中,我们将学习如何创建流。

从值创建流

我们可以使用Stream接口的()从单个值和多个值创建顺序流。

<T> Stream<T> of(T  t)
<T> Stream<T> of(T...values)

从方法签名,我们可以看到第一个of()方法从单个值创建流,而第二个of()方法从不同长度参数创建流

以下代码创建包含单个值的流。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream<String> stream  = Stream.of("www.w3cschool.cn");
    stream.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

以下代码创建具有四个字符串的流。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream<String> stream  = Stream.of("XML", "Java",  "CSS", "SQL");
    stream.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

以下代码从对象数组创建流。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    String[] names = { "XML", "Java", "SQL", "CSS" };
    Stream<String> stream = Stream.of(names);
    stream.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

流构建器

我们可以使用Stream.Builder<T>创建流。

以下代码创建流构建器。

Stream.Builder<String> builder = Stream.builder();
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream<String> stream  = Stream.<String>builder()
        .add("XML")
        .add("Java")
        .add("CSS")
        .add("SQL")
        .build();
    stream.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

IntStream范围

我们可以使用IntStream接口中的以下两种方法从一系列int值创建IntStream。

IntStream range(int start, int end)
IntStream rangeClosed(int start, int end).

它们创建一个包含开始和结束之间的有序整数的IntStream。

指定的结束在range()方法中是独占的,并且在rangeClosed()方法中是包含的。

以下代码使用这两种方法创建一个IntStream,它的整数为1,2,3,4和5作为其元素:

import java.util.stream.IntStream;

public class Main {
  public static void main(String[] args) {
    IntStream oneToFive  = IntStream.range(1, 6);
    //IntStream oneToFive  = IntStream.rangeClosed(1, 5);
    oneToFive.forEach(System.out::println);
  }
}

像IntStream接口一样,LongStream类还包含range()和rangeClosed()方法,它们接受类型为long的参数,并返回一个LongStream。

上面的代码生成以下结果。

img

空流

空流没有元素。

我们可以使用empty()静态方法从Stream接口以创建空的顺序流。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream<String> stream  = Stream.empty();
    stream.forEach(System.out::println);
  }
}

IntStream,LongStream和DoubleStream接口还包含一个empty()静态方法来创建一个空的基本类型流。

以下代码创建一个空的整数流。

IntStream numbers = IntStream.empty();

2.Java流 - Java函数流

我们可以有一个可以根据需要生成值的函数。

以下两种静态方法从Stream接口从函数生成无限流。

<T> Stream<T> iterate(T  seed, UnaryOperator<T>  f)
<T> Stream<T> generate(Supplier<T> s)

iterate()方法创建顺序有序流。

generate()方法创建一个顺序无序流。

IntStream,LongStream和DoubleStream包含iterate()和generate()方法,它们采用特定于其原始类型的参数生成值。

例如,在IntStream接口中定义了以下两种方法:

IntStream iterate(int seed,  IntUnaryOperator f)
IntStream generate(IntSupplier s)

Stream.iterate()

iterate()方法有两个参数:种子和函数。

种子是流的第一个元素。通过将函数应用于第一元素来生成第二元素。通过对第二元素应用函数来生成第三元素。

因此,元素是:seed,f(seed),f(f(seed)),f(f(f(seed)))…

以下代码创建了一个自然数流:

Stream<Long> naturalNumbers = Stream.iterate(1L, n -> n + 1);

limit(long maxSize)操作是产生另一个流的中间操作。

以下代码创建前10个自然数的流:

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream<Long> tenNaturalNumbers = Stream.iterate(1L, n  ->  n  + 1)
        .limit(10);

    tenNaturalNumbers.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

以下代码过滤从iterate函数生成的值。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.iterate(2L, n  ->  n  + 1)
    .filter(Main::isOdd)
    .limit(5)
    .forEach(System.out::println);
  }
  public static boolean isOdd(long number) {
    if (number % 2 == 0) {
      return false;
    }
    return true;
  }
}

上面的代码生成以下结果。

img

要从流中丢弃某些元素,请使用跳过操作。

skip(long n)是一个中间操作,跳过流的前n个元素。

以下代码使用skip跳过前100个奇数:

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.iterate(2L, n  ->  n  + 1)
    .filter(Main::isOdd)
    .skip(100)
    .limit(5)
    .forEach(System.out::println);
  }
  public static boolean isOdd(long number) {
    if (number % 2 == 0) {
      return false;
    }
    return true;
  }
}

上面的代码生成以下结果。

img

Stream.generate()

generate(Supplier<T> s)使用Supplier来生成无限顺序无序流。

以下代码打印五个随机数。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.generate(Math::random)
    .limit(5)
    .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

要生成基于上一个元素生成下一个元素的流,您需要使用存储最后生成元素的Supplier。

以下代码保留静态变量中的最后一个值。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.generate(Main::next)
    .limit(5)
    .forEach(System.out::println);

  }
  
  static int i=0;
  private static int next(){
    i++;
    return i;
  }
}

上面的代码生成以下结果。

img

java.util.Random类提供ints(),longs()和doubles()分别返回无限IntStream,LongStream和DoubleStream。

以下代码从从Random类的ints()方法返回的IntStream中打印了五个随机int值:

import java.util.Random;

public class Main {
  public static void main(String[] args) {
    new Random().ints()
    .limit(5)
    .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

我们可以使用Random的nextInt()方法类作为Supplier在generate()方法中实现相同。

import java.util.Random;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.generate(new Random()::nextInt)
    .limit(5)
    .forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

要仅使用基本值,请使用基本类型流接口的generate()方法。

import java.util.Random;
import java.util.stream.IntStream;

public class Main {
  public static void main(String[] args) {
    IntStream.generate(new Random()::nextInt)
    .limit(5)
    .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

生成重复值的无限流。

import java.util.stream.IntStream;

public class Main {
  public static void main(String[] args) {
    IntStream.generate(() ->  0)
    .limit(5)
    .forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

3.Java流 - Java集合流

来自数组的流

java.util.Arrays类包含用于从数组创建顺序流的stream()方法。

我们可以使用它来创建一个IntStream,一个LongStream,一个DoubleStream和一个Stream 。

下面的代码创建一个IntStream。

IntStream numbers = Arrays.stream(new int[]{1, 2, 3});

以下代码从int数组和String数组创建Stream 。

Stream<String> names = Arrays.stream(new String[] {"XML",   "Java"});

集合流

Collection接口包含stream()和parallelStream()方法,它们分别从Collection创建顺序流和并行流。

以下代码从一组字符串创建流:

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Set<String> names = new HashSet<>(); 
    names.add("XML");
    names.add("Java");

    Stream<String> sequentialStream  = names.stream();
    sequentialStream.forEach(System.out::println);

    Stream<String> parallelStream = names.parallelStream();
    parallelStream.forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

4.Java流 - Java字符串流

Char序列流

CharSequence接口的chars()返回一个IntStream,它的元素是表示字符的int值。

我们可以在String,StringBuilder和StringBuffer上使用chars()方法。

以下代码从字符串创建字符流,过滤掉所有数字和空格,然后打印剩余的字符:

public class Main {
  public static void main(String[] args) {
    String str = "5 123,123,qwe,1,123, 25";
    str.chars()
    .filter(n ->  !Character.isDigit((char)n) &&   !Character.isWhitespace((char)n))
    .forEach(n ->  System.out.print((char)n));

  }
}

上面的代码生成以下结果。

img

Regex流

java.util.regex.Pattern类中的splitAsStream(CharSequence input)方法返回其元素与模式匹配的String流。

以下代码通过使用正则表达式(“,”)拆分字符串来获取字符串流。

匹配的字符串打印在标准输出上。

import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    String str = "XML,CSS,HTML"; 
    Pattern.compile(",")
    .splitAsStream(str)
    .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

5.Java流 - Java文件流

来自Java 8的java.io和java.nio.file包添加了许多方法来支持使用流的I/O操作。

我们可以从文件中读取文本作为字符串流。流中的每个元素表示一行文本。

我们还可以使用流从JarFile读取JarEntry,我们可以读取目录中的条目作为Path流。

自动关闭

调用stream上的close()方法将关闭底层文件。

或者,我们可以在try-with-resources语句中创建流,以便自动关闭底层文件。

以下代码显示如何使用流读取文件的内容。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Path path = Paths.get("./Main.java");
    try (Stream<String> lines = Files.lines(path)) {
      lines.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

上面的代码生成以下结果。

img

以下代码显示如何使用流读取路径。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Path dir = Paths.get(".");
    System.out.printf("%nThe file tree for %s%n", 
        dir.toAbsolutePath());
    try (Stream<Path> fileTree = Files.walk(dir)) {
      fileTree.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

上面的代码生成以下结果。

img

三、java流操作

1.java流 - Java流操作

常用的流操作如下列出。

  • Distinct
    中间操作
    通过检查equals()方法返回由不同元素组成的流。
  • filter
    中间操作
    返回与指定谓词匹配的流。
  • flatMap
    中间操作
    生成流扁平化。
  • limit
    中间操作
    按数字截断流。
  • map
    中间操作
    对流执行一对一映射
  • peek
    中间操作
    应用调试的操作。
  • skip
    中间操作
    丢弃前n个元素并返回剩余流。如果此流包含少于请求的流,则返回空流。
  • sorted
    中间操作
    根据自然顺序或指定的比较器对流进行排序。对于有序流,排序是稳定的。
  • allMatch
    终端操作
    如果流中的所有元素都匹配指定的谓词,则返回true,否则返回false。如果流为空,则返回true。
  • anyMatch
    终端操作
    如果流中的任何元素与指定的谓词匹配,则返回true,否则返回false。如果流为空,则返回false。
  • findAny
    终端操作
    返回流中的任何元素。返回空流的一个空的Optional对象。
  • findFirst
    终端操作
    返回流的第一个元素。对于有序流,它返回第一个元素;对于无序流,它返回任何元素。
  • noneMatch
    终端操作
    如果流中没有元素匹配指定的谓词,则返回true,否则返回false。如果流为空,则返回true。
  • forEach
    终端操作
    对流中的每个元素应用操作。
  • reduce
    终端操作
    应用缩减操作以从流计算单个值。

流 Peek

我们可以使用Stream 接口的窥探(Consumer<?super T>action)方法调试流。

IntStream,LongStream和DoubleStream还包含一个peek()方法,它接受IntConsumer,LongConsumer和DoubleConsumer作为参数。

我们可以使用带有peek()方法的lambda表达式来记录元素。

以下代码使用peek()方法打印通过流管道的元素:

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    int sum = Stream.of(1, 2, 3, 4, 5)
        .peek(e -> System.out.println("Taking integer: " + e))
        .filter(n -> n % 2 == 1)
        .peek(e -> System.out.println("Filtered integer: " + e))
        .map(n -> n * n).peek(e -> System.out.println("Mapped integer: " + e))
        .reduce(0, Integer::sum);
    System.out.println("Sum = " + sum);

  }
}

上面的代码生成以下结果。

img

流 ForEach

forEach操作对流的每个元素执行操作。

Stream<T> 接口包含两种方法来执行forEach操作:

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

IntStream,LongStream和DoubleStream包含相同的方法。

forEach()方法不保证操作的顺序应用流中的每个元素。

forEachOrdered()方法按元素的顺序执行操作由流定义。

forEachOrdered()方法可能会减慢并行流中的处理速度。

以下代码打印员工列表中的女性详细信息:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {

    Employee.persons()
            .stream()
            .filter(Employee::isFemale)
            .forEach(System.out::println);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public boolean isFemale() {
    return this.gender == Gender.FEMALE;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码显示如何使用forEach()方法将所有女性的收入增加10%。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Employee> persons = Employee.persons();
    System.out.println("Before increasing the   income:   " + persons);

    persons.stream()
           .filter(Employee::isFemale)
           .forEach(p -> p.setIncome(p.getIncome() * 1.10));

    System.out.println("After increasing the   income:   " + persons);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public Gender getGender() {
    return gender;
  }

  public boolean isMale() {
    return this.gender == Gender.MALE;
  }

  public boolean isFemale() {
    return this.gender == Gender.FEMALE;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }
  public double getIncome() {
    return income;
  }

  public void setIncome(double income) {
    this.income = income;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

2.Java流 - Java流过滤器

过滤操作产生过滤流,即输入流的子集,其元素对于指定的谓词计算为true。

predicate是一个接受元素并返回布尔值的函数。

过滤的流具有与输入流相同的类型。

如果predicate对所有元素求值为false,它将生成一个空流。

以下代码仅在女性中使用员工流和过滤器。 它将女性映射到他们的名字,并将它们打印在标准输出上。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    Employee.persons()
            .stream()
            .filter(Employee::isFemale)
            .map(Employee::getName)
            .forEach(System.out::println);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Gender getGender() {
    return gender;
  }

  public boolean isMale() {
    return this.gender == Gender.MALE;
  }

  public boolean isFemale() {
    return this.gender == Gender.FEMALE;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }

  public LocalDate getDob() {
    return dob;
  }

  public void setDob(LocalDate dob) {
    this.dob = dob;
  }

  public double getIncome() {
    return income;
  }

  public void setIncome(double income) {
    this.income = income;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

对于下面的代码

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    Employee.persons()
    .stream()
    .filter(Employee::isMale)
    .filter(p ->  p.getIncome() > 5000.0)
    .map(Employee::getName)
    .forEach(System.out::println);
  }
}
...
...

我们可以将两个滤波器组合为一个具有AND运算。

public class Main {
  public static void main(String[] args) {
    Employee.persons()
    .stream()
    .filter(p ->  p.isMale() &&   p.getIncome() > 5000.0)
    .map(Employee::getName)
    .forEach(System.out::println);
  }
}

3.Java流 - Java流映射

映射操作对每个元素应用函数以产生另一流。

输入和输出流中的元素数量是相同的。

该操作不修改输入流的元素。

您可以使用Stream 接口的以下方法之一对流应用地图操作:

<R> Stream<R> map(Function<? super T,? extends R> mapper)
DoubleStream  mapToDouble(ToDoubleFunction<? super T> mapper)
IntStream     mapToInt(ToIntFunction<? super T> mapper)
LongStream    mapToLong(ToLongFunction<? super T> mapper)

IntStream,LongStream和DoubleStream也定义了映射函数。支持对IntStream进行映射操作的方法如下:

IntStream     map(IntUnaryOperator mapper)
DoubleStream  mapToDouble(IntToDoubleFunction mapper)
LongStream    mapToLong(IntToLongFunction   mapper)
<U> Stream<U> mapToObj(IntFunction<? extends  U>  mapper)

以下代码显示如何使用map()将IntStream中的元素映射到其正方形,并在标准输出上打印映射流。

import java.util.stream.IntStream;

public class Main {
  public static void main(String[] args) {
    IntStream.rangeClosed(1, 5)
             .map(n -> n * n)
             .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

以下代码将员工流映射到其名称,并打印映射流。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    Employee.persons()
            .stream()
            .map(Employee::getName)
            .forEach(System.out::println);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Gender getGender() {
    return gender;
  }

  public boolean isMale() {
    return this.gender == Gender.MALE;
  }

  public boolean isFemale() {
    return this.gender == Gender.FEMALE;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }

  public LocalDate getDob() {
    return dob;
  }

  public void setDob(LocalDate dob) {
    this.dob = dob;
  }

  public double getIncome() {
    return income;
  }

  public void setIncome(double income) {
    this.income = income;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

流flatMap

Streams map()操作创建一个一对一映射。

streams flatMap()支持一对多映射。 它将每个元素映射到流,然后将流的流平面化为流。

下面的代码映射了三个数字的流:1,2和3,以产生包含数字及其下一个数字的流。 输出流应为1,2,2,3,3,4。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.of(1, 2, 3)
    .flatMap(n -> Stream.of(n, n+1))
    .forEach(System.out::println);

  }
}

上面的代码生成以下结果。

img

以下代码显示如何将字符串流转换为字符流。

import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.of("XML", "Java",  "CSS")
        .map(name  ->  name.chars())
        .flatMap(intStream ->  intStream.mapToObj(n ->  (char)n))
        .forEach(System.out::println); 

  }
}

代码将字符串映射到String类的chars()方法的IntStream返回。

map()方法的输出是Stream< IntStream>

flatMap()方法将Stream<IntStream> 映射到Stream 字符>>,最后,将其平坦化以生成Stream。

上面的代码生成以下结果。

img

以下代码将字符串值流映射到IntStreams,然后将IntStream映射到字符流。

import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Stream.of("XML", "Java",  "CSS")
        .flatMap(name ->  IntStream.range(0, name.length())
        .mapToObj(name::charAt))
        .forEach(System.out::println);
  }
}

上面的代码生成以下结果。

img

4.Java流 - Java流组合

reduce()操作组合流中的所有元素以产生单个值。

reduce操作采用两个称为种子(初始值)和累加器的参数。

累加器是一个函数。如果流是空的,种子是结果。

种子和一个元素被传递给累加器,它返回部分结果。然后将部分结果和下一个元素传递给累加器函数。

这重复,直到所有元素被传递到累加器。累加器返回的最后一个值是reduce操作的结果。

流相关接口包含两个称为reduce()和collect()的方法来执行通用reduce操作。

诸如sum(),max(),min(),count()等方法在IntStream,LongStream和DoubleStream接口中定义。

count()方法适用于所有类型的流。

Stream 接口包含一个reduce()方法来执行reduce操作。该方法有三个重载版本:

T  reduce(T identity, BinaryOperator<T> accumulator)
<U> U reduce(U identity, BiFunction<U,? super  T,U> accumulator, BinaryOperator<U> combiner)
Optional<T> reduce(BinaryOperator<T> accumulator)

第一个版本的reduce()方法使用一个标识和一个累加器作为参数,并将流reduce为同一类型的单个值。

import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Integer> numbers  = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
    .reduce(0, Integer::sum); 
    System.out.println(sum);
  }
}

上面的代码生成以下结果。

img

计算所有员工的收入总和。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    double sum = Employee.persons()
        .stream()
        .map(Employee::getIncome)
        .reduce(0.0, Double::sum);
    System.out.println(sum);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

第二个版本的reduce方法如下所示允许我们执行一个map操作,随后执行reduce操作。

<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

第三个参数用于组合部分结果当并行执行缩减操作时。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    double sum = Employee.persons()
        .stream()
        .reduce(0.0, (partialSum, person) -> partialSum + person.getIncome(), Double::sum); 
    System.out.println(sum);

  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public void setIncome(double income) {
    this.income = income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);
    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);
    return persons;
  }
}

上面的代码生成以下结果。

img

Java流映射并行reduce

Java Streams API支持并行映射缩减操作。

当使用以下reduce方法时,每个线程使用累加器累加部分结果。最后,组合器用于组合来自所有线程的部分结果以获得结果。

<U> U reduce(U identity, BiFunction<U,? super  T,U> accumulator, BinaryOperator<U> combiner)

以下代码显示了如何顺序并行reduce操作工作。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    double sum = Employee
        .persons()
        .stream()
        .reduce(
            0.0,
            (Double partialSum, Employee p) -> {
              double accumulated = partialSum + p.getIncome();
              System.out.println(Thread.currentThread().getName()
                  + "  - Accumulator: partialSum  = " + partialSum
                  + ",  person = " + p + ", accumulated = " + accumulated);
              return accumulated;
            },
            (a, b) -> {
              double combined = a + b;
              System.out.println(Thread.currentThread().getName()
                  + "  - Combiner:  a  = " + a + ", b  = " + b
                  + ", combined  = " + combined);
              return combined;
            });
    System.out.println("--------------------------------------");
    System.out.println(sum);

    sum = Employee
        .persons()
        .parallelStream()
        .reduce(
            0.0,
            (Double partialSum, Employee p) -> {
              double accumulated = partialSum + p.getIncome();
              System.out.println(Thread.currentThread().getName()
                  + "  - Accumulator: partialSum  = " + partialSum
                  + ",  person = " + p + ", accumulated = " + accumulated);
              return accumulated;
            },
            (a, b) -> {
              double combined = a + b;
              System.out.println(Thread.currentThread().getName()
                  + "  - Combiner:  a  = " + a + ", b  = " + b
                  + ", combined  = " + combined);
              return combined;
            });
    System.out.println(sum);
  }
}
class Employee {
  public static enum Gender {
    MALE, FEMALE
  }
  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

流reduce没有默认值

第三个版本的reduce()如下列方法用于执行没有默认值的缩减操作。

reduce(BinaryOperator<T> accumulator)

如果流是空的,我们不能使用默认值为0。

Optional<T>用于包装结果或不存在结果。

以下代码显示如何计算流中的整数的最大值:

import java.util.Optional;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).reduce(Integer::max);

    if (max.isPresent()) {
      System.out.println("max = " + max.get());
    } else {
      System.out.println("max is not  defined.");
    }
    
    max = Stream.<Integer> empty().reduce(Integer::max);
    if (max.isPresent()) {
      System.out.println("max = " + max.get());
    } else {
      System.out.println("max is not  defined.");
    }
    
  }
}

上面的代码生成以下结果。

img

以下代码打印员工列表中最高收入者的详细信息。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    Optional<Employee> person = Employee
        .persons()
        .stream()
        .reduce((p1, p2) -> p1.getIncome() > p2.getIncome() ? p1 : p2);
    if (person.isPresent()) {
      System.out.println("Highest earner: " + person.get());
    } else {
      System.out.println("Could not  get   the   highest earner.");
    }
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

5.Java流 - Java流聚合

要计算数字流上的和,max,min,average等,我们可以将非数字流映射到数值流类型(IntStream,LongStream或DoubleStream),然后使用专门的方法。

以下代码计算收入的总和。 mapToDouble()方法将Stream<Employee>转换为DoubleStream。对DoubleStream调用sum()方法。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    double totalIncome = Employee.persons()
        .stream()
        .mapToDouble(Employee::getIncome)
        .sum(); 
    System.out.println("Total Income:  "  + totalIncome);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

要获取流的最小值和最大值,使用特定流的min()和max()方法。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    Optional<Employee> person = Employee.persons().stream()
        .max(Comparator.comparingDouble(Employee::getIncome));

    if (person.isPresent()) {
      System.out.println("Highest earner: " + person.get());
    } else {
      System.out.println("Could not  get   the   highest earner.");
    }
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

下面的代码打印了最高的收入员工列表使用DoubleStream的max()方法:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.OptionalDouble;

public class Main {
  public static void main(String[] args) {
    OptionalDouble income = 
       Employee.persons()
               .stream()
               .mapToDouble(Employee::getIncome).max();

    if (income.isPresent()) {
      System.out.println("Highest income:   " + income.getAsDouble());
    } else {
      System.out.println("Could not  get   the   highest income.");
    }
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

6.Java流计数

Streams通过count()方法支持计数操作,该方法将流中的元素数返回为long。

以下代码显示employee流中的元素数量。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    long personCount = Employee.persons().stream().count();
    System.out.println("Person count: " + personCount);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

下面的代码使用map()方法来计算流中的元素数。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    long  personCount = Employee.persons()
        .stream()
        .mapToLong(p ->  1L)
        .sum();
    System.out.println(personCount);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

下面的代码使用了map()和reduce()方法来实现计数操作。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    long  personCount = Employee.persons()
        .stream()
        .map(p  ->  1L)
        .reduce(0L,  Long::sum);
    System.out.println(personCount);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码使用reduce()方法来实现计数操作。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    long  personCount = Employee.persons()
        .stream()
        .reduce(0L, (partialCount,  person) ->  partialCount + 1L,  Long::sum);
    System.out.println(personCount);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

7.Java流 - Java流收集器

要在Stream中对数据进行分组,我们可以使用 collect()方法的Stream接口。

collect()方法重载了两个版本:

<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
<R,A> R collect(Collector<?  super T,A,R> collector)

collect()方法的第一个版本有三个参数:

  • 供应商提供一个可变容器来存储结果。
  • 累加器,将结果累积到可变容器中。
  • 组合器,当并行使用时组合部分结果。

我们使用以下步骤在ArrayList 中收集员工姓名。

首先,创建一个供应商,它使用以下语句之一返回一个ArrayList< String>以创建供应商:

Supplier<ArrayList<String>> supplier = () -> new ArrayList<>();

要么

Supplier<ArrayList<String>> supplier = ArrayList::new;

第二,创建一个累加器,它接收两个参数,它们是从供应商返回的容器(在这种情况下为ArrayList )。 和流的元素。

累加器将名称添加到列表中。

BiConsumer<ArrayList<String>, String>  accumulator = (list, name)  ->  list.add(name);
BiConsumer<ArrayList<String>, String>  accumulator = ArrayList::add;

最后,组合器将结果组合成一个ArrayList<String>

组合器仅用于并行流。

以下代码显示如何使用collect()方法来收集列表中所有员工的姓名。

import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<String> names = Employee.persons()
        .stream()
        .map(Employee::getName)
        .collect(ArrayList::new,  ArrayList::add, ArrayList::addAll);
    System.out.println(names);

  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

8.收集器接口

第二个版本的collect()将Collector接口的一个实例作为参数。

Streams API提供了一个名为Collectors的实用程序类,为常用的收集器提供了开箱即用的实现。

三种最常用的方法之一收集器类是toList(),toSet()和toCollection()。

  • toList()方法返回收集列表中数据的收集器。
  • toSet()方法返回在集合中收集数据的收集器。
  • toCollecton()返回一个供应商,返回一个集合用于收集数据。

以下代码收集列表中的所有员工姓名。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<String> names = Employee.persons()
        .stream()
        .map(Employee::getName)
        .collect(Collectors.toList());
     System.out.println(names);

  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码收集Set中的所有名称,它只保留唯一的元素。

Set<String> uniqueNames  = Person.persons()
                        .stream()
                        .map(Person::getName)
                        .collect(Collectors.toSet());
System.out.println(uniqueNames); 

我们可以使用toCollection()方法在排序集合中收集名称,如下所示:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    SortedSet<String> uniqueSortedNames=   Employee.persons()
        .stream()
        .map(Employee::getName)
        .collect(Collectors.toCollection(TreeSet::new));
        System.out.println(uniqueSortedNames);
    System.out.println(uniqueSortedNames);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

9.Java流 - Java流统计

java.util包包含三个类来收集统计信息:

  • DoubleSummaryStatistics
  • LongSummaryStatistics
  • IntSummaryStatistics

我们可以使用它们来计算任何数字数据组的摘要统计信息。

以下代码显示如何计算多个双精度值的统计信息。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    DoubleSummaryStatistics stats = new DoubleSummaryStatistics();
    stats.accept(100.0);
    stats.accept(300.0);
    stats.accept(230.0);
    stats.accept(532.0);
    stats.accept(422.0);

    long count = stats.getCount();
    double sum = stats.getSum();
    double min = stats.getMin();
    double avg = stats.getAverage();
    double max = stats.getMax();

    System.out.printf(
        "count=%d, sum=%.2f,  min=%.2f,  average=%.2f, max=%.2f%n", count, sum,
        min, max, avg);
  }
}

上面的代码生成以下结果。

count=5,sum=1584.00, min=100.00, average=316.80, max=532.00

流摘要统计

摘要统计类设计为与流一起使用。

它们包含组合两个摘要统计信息的combine()方法。

以下代码显示如何计算收入总结统计。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    DoubleSummaryStatistics incomeStats = Employee.persons()
        .stream()
        .map(Employee::getIncome)
        .collect(DoubleSummaryStatistics::new, 
                 DoubleSummaryStatistics::accept, 
                 DoubleSummaryStatistics::combine);
     System.out.println(incomeStats);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }
  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);
    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);
    return persons;
  }
}

上面的代码生成以下结果。

img

数字流摘要统计

Collectors类包含要计算的方法数字数据的特定类型的摘要统计信息。

  • Collectors.summarizingDouble()返回DoubleSummaryStatistics。
  • Collectors.summarizingLong()返回一个LongSummaryStatistics。
  • Collectors.summarizingInt()返回一个IntSummaryStatistics。

Collectors类包含方法,如counting(),summingDouble(),summingInt(),summingLong(),averagingDouble(),averagingLong(),averagingInt(),minBy()和maxBy()返回一个收集器来执行一种特定类型的汇总计算。

以下代码显示如何计算摘要统计信息收入。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    DoubleSummaryStatistics incomeStats = Employee.persons()
        .stream()
        .collect(Collectors.summarizingDouble(Employee::getIncome));
    System.out.println(incomeStats);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

10.Java流 - Java流收集映射

我们可以从流中收集数据到映射。

在三个版本中重载的toMap()方法Collectors类返回一个收集器以在Map中收集数据。

toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M>  mapSupplier)
toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)

第一个版本有两个参数。这两个参数都是一个函数。

第一个参数将流元素映射到映射中的键。

第二个参数将流元素映射到映射中的值。

如果重复键,则抛出IllegalStateException。

以下代码在Map<long,String>中收集员工的数据,其中的关键字是员工的ID,值是员工的姓名。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Long,String>  idToNameMap  = Employee.persons()
        .stream()
        .collect(Collectors.toMap(Employee::getId,  Employee::getName));
     System.out.println(idToNameMap);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public long getId() {
    return id;
  }
  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

下面列出的第二种形式的toMap具有额外的合并函数。

toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)

合并函数传递重复键的旧值和新值。 该函数应合并两个值,并返回将用于键的新值。

以下代码显示如何连接所有男性和女性的名称。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender,String> genderToNamesMap  = 
    Employee.persons()
            .stream()
            .collect(Collectors.toMap(Employee::getGender,
                                      Employee::getName,
                                      (oldValue, newValue)  ->  String.join(", ", oldValue,  newValue))); 
    System.out.println(genderToNamesMap);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Gender getGender() {
    return gender;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

下面列出的第三个版本允许我们使用供应商提供一个Map对象。

toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M>  mapSupplier)

以下代码按性别总结人数。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, Long> countByGender  = Employee.persons()
        .stream()
        .collect(Collectors.toMap(Employee::getGender, p  ->  1L, (oldCount, newCount)  ->  newCount+oldCount));

    System.out.println(countByGender);
  }
}
class Employee {
  public static enum Gender {
    MALE, FEMALE
  }
  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;
  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public Gender getGender() {
    return gender;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);
    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);
    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码在映射中按性别取得最高收入。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, Employee>  highestEarnerByGender = Employee.persons()
        .stream()
        .collect(Collectors.toMap(Employee::getGender, Function.identity(), 
                                  (oldPerson, newPerson)  -> newPerson.getIncome() > oldPerson.getIncome() ? newPerson : oldPerson));
    System.out.println(highestEarnerByGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public Gender getGender() {
    return gender;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

11.Java流连接

Collectors类的joining()方法返回一个收集器,它连接CharSequence流,并将结果作为String返回。

joining()方法是重载的,它有三个版本:

  • joining()
    连接所有元素
  • joining(CharSequence delimiter)
    使用在两个元素之间使用的分隔符。
  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
    使用分隔符,前缀和后缀。 前缀将添加到开头,后缀将添加到结尾。

以下代码显示如何使用joining()方法。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    List<Employee> persons  = Employee.persons(); 
    String names = persons.stream()
        .map(Employee::getName)
        .collect(Collectors.joining());

     String  delimitedNames = persons.stream()
        .map(Employee::getName)
        .collect(Collectors.joining(", "));

     String  prefixedNames = persons.stream()
        .map(Employee::getName)
        .collect(Collectors.joining(", ", "Hello ",  ".  Goodbye."));

     System.out.println("Joined names:  "  + names); 
     System.out.println("Joined,  delimited names:  "  + delimitedNames); 
     System.out.println(prefixedNames);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

12.Java流分组

Collectors类中的groupingBy()方法返回一个收集器,用于在将数据收集到Map之前对数据进行分组。 它类似于SQL中的“group by”子句。

groupingBy()方法是重载的,它有三个版本:

groupingBy(Function<? super  T,?  extends K>  classifier)
groupingBy(Function<? super  T,?  extends K>  classifier,  Collector<? super T,A,D> downstream)
groupingBy(Function<? super  T,?  extends K>  classifier, Supplier<M>  mapFactory, Collector<? super T,A,D> downstream)

在前两个版本中,收集器负责为您创建Map对象。第三个版本允许我们指定一个用作工厂的Supplier来获取Map对象。

classifier 函数生成地图中的键。collector对与每个键相关联的值执行简化操作。

以下代码显示了如何按性别和计算每个组中的人数。

Collectors类的counting()方法返回要计数的Collector流中的元素数。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, Long> countByGender  = Employee.persons()
        .stream()
        .collect(Collectors.groupingBy(Employee::getGender, Collectors.counting())); 
    System.out.println(countByGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public Gender getGender() {
    return gender;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码显示如何按性别对person的名称进行分组:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, String>  namesByGender = Employee.persons()
        .stream()
        .collect(Collectors.groupingBy(Employee::getGender, 
                                       Collectors.mapping(Employee::getName, Collectors.joining(", "))));
    System.out.println(namesByGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public Gender getGender() {
    return gender;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码显示了如何在列表中收集员工姓名。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, List<String>>  namesByGender = 
        Employee.persons()
        .stream()
        .collect(Collectors.groupingBy(Employee::getGender, 
                                       Collectors.mapping(Employee::getName, Collectors.toList())));

    System.out.println(namesByGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public Gender getGender() {
    return gender;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码按性别分组人员。在每个性别组中,它创建另一个组他们出生的月份,并列出了在这个组出生的人的名字。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    Map personsByGenderAndDobMonth
    = Employee.persons()
    .stream()
    .collect(Collectors.groupingBy(Employee::getGender, 
                                   Collectors.groupingBy(p ->  p.getDob().getMonth(),  
                                   Collectors.mapping(Employee::getName,Collectors.joining(", ")))));

    System.out.println(personsByGenderAndDobMonth);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public Gender getGender() {
    return gender;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }

  public LocalDate getDob() {
    return dob;
  }

  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

以下代码显示如何按性别分组汇总收入统计。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
  public static void main(String[] args) {
    Map<Employee.Gender, DoubleSummaryStatistics>  incomeStatsByGender = Employee.persons()
        .stream()
        .collect(Collectors.groupingBy(Employee::getGender, Collectors.summarizingDouble(Employee::getIncome)));

    System.out.println(incomeStatsByGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public Gender getGender() {
    return gender;
  }
  public double getIncome() {
    return income;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

13.Java流 - Java流分区

分区是分组的一种特殊情况。

分组数据基于从函数返回的键。可能有很多组。

分区仅处理基于谓词的两个组。评估为true的值为一个组,false为另一个组。

partitioningBy()方法,它收集映射中的数据,其键的总是布尔类型,在两个版本中重载。

partitioningBy(Predicate<? super T> predicate)
partitioningBy(Predicate<? super T> predicate,  Collector<? super T,A,D> downstream)

第一个版本的partitioningBy()方法返回基于谓词执行分区的收集器。

以下代码显示如何根据性别对employee进行分区。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
  public static void main(String[] args) {
    Map<Boolean,  List<Employee>>  partionedByMaleGender = 
    Employee.persons()
            .stream()
            .collect(Collectors.partitioningBy(Employee::isMale)); 
    System.out.println(partionedByMaleGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

第二个版本允许我们指定另一个可以执行还原操作的收集器。

以下代码显示如何按性别分区员工,并以逗号分隔的字符串收集其名称:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
  public static void main(String[] args) {
    Map<Boolean,String> partionedByMaleGender = Employee.persons()
        .stream()
        .collect(Collectors.partitioningBy(Employee::isMale, 
                   Collectors.mapping(Employee::getName, Collectors.joining(", "))));
    System.out.println(partionedByMaleGender);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img****

14.Java流转换收集器结果

我们可以将收集器的结果转换为不同的类型。

Collectors类的collectingAndThen()方法定义如下。

collectingAndThen(Collector<T,A,R> downstream, Function<R,RR>  finisher)

第一个参数是收集数据的收集器。 第二个参数是转换结果的转换器。

以下代码返回收集数据的不可更改视图。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
  public static void main(String[] args) {
    List<String> names = Employee.persons()
        .stream()
        .map(Employee::getName)
        .collect(Collectors.collectingAndThen(Collectors.toList(),
             result ->  Collections.unmodifiableList(result))); 
    System.out.println(names);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }

  public String getName() {
    return name;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

15.Java流 - Java流查找

Streams API支持对流元素的不同类型的查找操作。

Stream接口中的以下方法用于执行查找操作:

Optional<T>   findAny()
Optional<T>   findFirst()

诸如IntStream,LongStream和DoubleStream的原始类型流也包含与谓词一起使用的相同方法和用于原语类型的可选方法。

所有查找操作都是终端操作。它们也是短路操作。短路操作可以不必处理整个流以返回结果。

以下代码显示如何对流执行查找操作。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Main {
  public static void main(String[] args) {
    List<Employee> persons = Employee.persons();
    // Find any male
    Optional<Employee> anyMale = persons.stream().filter(Employee::isMale).findAny();
    if (anyMale.isPresent()) {
      System.out.println("Any male:   " + anyMale.get());
    } else {
      System.out.println("No male  found.");
    }
    // Find the first male
    Optional<Employee> firstMale = persons.stream().filter(Employee::isMale).findFirst();
    if (firstMale.isPresent()) {
      System.out.println("First male:   " + anyMale.get());
    } else {
      System.out.println("No male  found.");
    }
  }
}
class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

16.Java流 - Java流匹配

Streams API支持对流元素执行不同类型的匹配操作。

Stream接口中的以下方法用于执行匹配操作:

boolean allMatch(Predicate<? super T> predicate)
boolean anyMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super  T> predicate)

诸如IntStream,LongStream和DoubleStream的原始类型流也包含与谓词一起使用的相同方法和用于原语类型的可选方法。

所有匹配操作都是终端操作。它们也是短路操作。短路操作可以不必处理整个流以返回结果。

以下代码显示如何对流执行匹配操作。

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class Main {
  public static void main(String[] args) {
    List<Employee> persons = Employee.persons();

    // Check if all persons are males
    boolean allMales = persons.stream().allMatch(Employee::isMale);
    System.out.println("All  males: " + allMales);

    // Check if any person was born in 1971
    boolean anyoneBornIn1971 = persons.stream().anyMatch(p -> p.getDob().getYear() == 1971);
    System.out.println("Anyone born  in 1971:  " + anyoneBornIn1971);

  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }

  public LocalDate getDob() {
    return dob;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

四、Java并行流

Java流 - Java并行流

流可以是顺序的或并行的。

顺序流上的操作由一个线程串行处理。

使用多个线程并行处理并行流上的操作。

默认情况下,Streams API中的大多数方法都会生成顺序流。要从集合(如列表或集合)创建并行流,调用Collection接口的parallelStream()方法。

对流使用parallel()方法将顺序流转换为并行流。

对流使用sequential()方法将并行流转换为顺序流。

以下代码显示如何对流进行串行处理:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    String names = Employee.persons()              
        .stream()                  
        .filter(Employee::isMale)  
        .map(Employee::getName)    
        .collect(Collectors.joining(", ")); 
    System.out.println(names);

    names = Employee.persons()                 
        .parallelStream()    
        .filter(Employee::isMale)
        .map(Employee::getName)  
        .collect(Collectors.joining(", ")); 
    System.out.println(names);

  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }

  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }

  @Override
  public String toString() {
    String str = String.format("(%s, %s,  %s,  %s,  %.2f)\n", id, name, gender,
        dob, income);
    return str;
  }
}

上面的代码生成以下结果。

img

以下代码显示如何混合串行和并行流:

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
  public static void main(String[] args) {
    String names = Employee.persons()                // The data source
        .stream()                  // Produces a  sequential  stream
        .filter(Employee::isMale)   // Processed in serial
        .parallel()               // Produces a  parallel  stream
        .map(Employee::getName)       // Processed in parallel
        .collect(Collectors.joining(", "));  // Processed in parallel
    System.out.println(names);
  }
}

class Employee {
  public static enum Gender {
    MALE, FEMALE
  }
  private long id;
  private String name;
  private Gender gender;
  private LocalDate dob;
  private double income;

  public Employee(long id, String name, Gender gender, LocalDate dob,
      double income) {
    this.id = id;
    this.name = name;
    this.gender = gender;
    this.dob = dob;
    this.income = income;
  }
  public String getName() {
    return name;
  }
  public boolean isMale() {
    return this.gender == Gender.MALE;
  }
  public static List<Employee> persons() {
    Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971,
        Month.JANUARY, 1), 2343.0);
    Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972,
        Month.JULY, 21), 7100.0);
    Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973,
        Month.MAY, 29), 5455.0);
    Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974,
        Month.OCTOBER, 16), 1800.0);
    Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975,
        Month.DECEMBER, 13), 1234.0);
    Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976,
        Month.JUNE, 9), 3211.0);

    List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6);

    return persons;
  }
}

上面的代码生成以下结果。

img

五.Stream集合流操作整理全集

  • Java 8 API添加了一个新的抽象称为流 Stream ,可以让你以一种声明的方式处理数据;
  • Stream 是一个来自 数据源 的元素队列并支持 聚合 操作,可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码;

Stream 和 parallelStream

  • Stream:串行流单线程,线程安全,适合阻塞任务、重量级任务;
  • parallelStream:并行流多线程,线程不安全,其底层使用Fork/Join框架实现,适合较单纯的数据处理任务;

注意事项

  • 流操作支持 lamda 书写格式,例如:

    1)普通格式:	map(str -> str.toUpperCase()),lamda简写格式:map(String::toUpperCase)2)普通格式:	x ->{System.out.println(x);},lamda简写格式:System.out::println)
    
  • 操作元素可以多个同时进行,即在过滤的同时,也可以修改值;

  • stream 和 parallelStream,操作方式雷同,区别在于 串行流与并行流;

  • 参考网址:https://www.runoob.com/java/java8-streams.html

操作元素

(1)中间操作:流中间操作在应用到流上,返回一个新的流;

  • map:通过一个 Function 把一个元素类型为 T的流转换成元素类型为 R的流。

  • flatMap:扁平化流,通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流,再把这些转换之后的流合并。

  • filter:过滤流中的元素,只保留满足由 Predicate 所指定的条件的元素。

  • distinct:筛选,通过流所生成元素的hashCode()和equals去除重复元素

  • limit:截断流使其最多只包含指定数量的元素。

  • skip:跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补

  • sorted:对流进行排序。

  • peek:返回的流与原始流相同。当原始流中的元素被消费时,会首先调用 peek 方法中指定的 Consumer 实现对元素进行处理。

  • dropWhile:从原始流起始位置开始删除满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。

  • takeWhile:从原始流起始位置开始保留满足指定 Predicate 的元素,直到遇到第一个不满足 Predicate 的元素。

(2)终结操作:终结操作产生最终的结果;

  • forEach:遍历,自定义操作
  • allMatch:检查是否匹配所有元素
  • anyMatch:检查是否至少匹配一个元素
  • noneMatch:检查是否没有匹配所有元素
  • findFirst:返回第一个元素
  • findAny:返回当前流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中最大值
  • min:返回流中最小值
  • reduce:归约,递归操作,将流的每个元素反复结合形成得到新值
  • collect:收集,汇总操作(返回新集合、分组),接收一个Collector接口实现

说明

一、集合操作: ( List<Map<String,Object>> list ) 和 ( List listModel )

  • listMap>filter:过滤,返回新集合

    List<Map<String,Object>> resu = list.stream().filter(f -> f.get("sex").equals("女")).collect(Collectors.toList());
    System.out.println("resu:"+JSON.toJSONString(resu));
    
  • listMap>map:修改对象值,返回新集合

    List<String[]> resu1 = list.stream().map(ma->((String) ma.get("name")).split("")).collect(Collectors.toList());
    System.out.println("resu1:"+JSON.toJSONString(resu1));
    
  • listMap>flatMap:修改对象值,扁平化处理(即map操作的所有单个流,都会扁平化合并成一个流,映射成流的内容),返回新集合

    List<String> resu2 = list.stream().map(ma->((String) ma.get("name")).split("")).flatMap(Arrays::stream).collect(Collectors.toList());
    System.out.println("resu2:"+JSON.toJSONString(resu2));
    
  • listMap>map:修改对象值,过滤重复对象值,返回新集合

    List<String> resu3 = list.stream().map(ma->((String)ma.get("name"))).distinct().collect(Collectors.toList());
    System.out.println("过滤重复值,resu3:"+JSON.toJSONString(resu3));
    
  • listModel>map+forEach:修改对象值,遍历集合

    listModel.stream().map(Test::getName).forEach(System.out::println);
    
  • listModel>sort:根据分数排序,升序,返回新集合

    List<Test> resu5 = listModel.stream().sorted(Comparator.comparing(Test::getGrade)).collect(Collectors.toList());
    System.out.println("根据分数排序,升序,返回新集合,resu5:"+JSON.toJSONString(resu5));
    
  • listModel>sort:根据分数排序,倒序,返回新集合

    List<Test> resu6 =listModel.stream().sorted(Comparator.comparing(Test::getGrade).reversed()).collect(Collectors.toList());
    System.out.println("根据分数排序,倒序,返回新集合,resu6:"+JSON.toJSONString(resu6));
    
  • listMap>sort:根据分数排序,升序,返回新集合

    List<Map<String,Object>> resu7 = list.stream().sorted((o1, o2) ->((Integer)o1.get("grade")).compareTo((Integer)o2.get("grade"))).collect(Collectors.toList());
    System.out.println("根据分数排序,升序,返回新集合,resu7:"+JSON.toJSONString(resu7));
    
  • listModel>findFirst:查找符合条件的第一个元素,返回元素

    Map<String,Object>  resu11= list.stream().filter(x -> x.get("sex").equals("女")).findFirst().orElseGet(null);
    System.err.println("查找符合条件的第一个元素,返回元素,resu11:"+(resu11==null?"null":resu11.get("name")));
    
  • listModel>count:查找符合条件的元素,返回个数

     long  resu12= list.stream().filter(x -> x.get("sex").equals("女")).count();
     System.err.println("查找符合条件的元素,返回个数,resu12:"+resu12);
    
  • listModel>max:查找符合条件的最大元素,返回元素

    Integer maxGrade = listModel.stream().map(x->x.getGrade()).max(Integer::compareTo).orElse(0);
    System.err.println("查找符合条件的最大元素,返回元素,maxGrade:"+maxGrade);
    Test maxGradeModel = listModel.stream().max(Comparator.comparing(Test::getGrade)).orElse(null);
    System.err.println("查找符合条件的最大元素,返回元素,maxGradeModel:"+(maxGradeModel==null?"无":maxGradeModel.getName()));
    
  • listModel>min:查找符合条件的最小元素,返回元素

    Integer minGrade = listModel.stream().map(x->x.getGrade()).min(Integer::compareTo).orElse(0);
    System.err.println("查找符合条件的最小元素,返回元素,minGrade:"+minGrade);
    
  • listMap>max:查找符合条件的最大元素,返回元素

     Map<String,Object> maxGradeMap = list.stream().max((o1, o2) -> ((Integer)o1.get("grade")).compareTo((Integer)o2.get("grade"))).orElse(null);
     System.out.println("查找符合条件的最大元素,返回元素,maxGradeMap:"+(maxGradeMap==null?"无":maxGradeMap.get("name")));
    
  • listMap>reduce:计算分数总数,返回总数

     //Integer gradeSum = list.stream().map(x -> (Integer)x.get("grade")).reduce(Integer::sum).orElse(0);
     Integer gradeSum = listModel.stream().map(Test::getGrade).reduce(Integer::sum).orElse(0);
     System.err.println("计算分数总和,返回总数,gradeSum:"+gradeSum);
    
  • listMap>collect>groupBy:分组统计,返回分组集合

     //Map<Object, List<Map<String,Object>>> sexMap = list.stream().collect(Collectors.groupingBy(x->x.get("sex")));
     Map<String, List<Test>> sexMap = listModel.stream().collect(Collectors.groupingBy(Test::getSex));
     System.err.println("根据性别分组,返回每种性别对应对象集合,sexMap:"+JSON.toJSONString(sexMap));
    
  • listMap>collect>groupBy:分组统计,返回分组总分数

     //Map<Object, Integer> sexMapSum = list.stream().collect(Collectors.groupingBy(x->x.get("sex"),Collectors.summingInt (x->(Integer)x.get("grade"))));
     Map<Object, Integer> sexMapSum = listModel.stream().collect(Collectors.groupingBy(Test::getSex,Collectors.summingInt(Test::getGrade)));
     System.err.println("根据性别分组,返回分组总分数,sexMapSum:"+JSON.toJSONString(sexMapSum));
    

二、Map操作:Map<String,Object> map

  • Map>forEach:遍历map

    map1.forEach((k,v)->System.out.println("遍历map:"+k+","+v));
    
  • Map>forEach:流遍历map

    map1.entrySet().stream().forEach(x -> System.out.println("流遍历map:"+x.getValue()));
    

分组操作

  • 实体类对象

    @Data
    public class Employee {
       private String name;   // 姓
       private String city;   // 城市
       private Integer sales;  // 销售额
    }
    
  • 方法一、groupingBy(Function)
    一个参数:一个分组器,使用提供的字段对集合元素进行分组,返回一个Map<字段,相同字段值的元素集>

    Map<String, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getCity));
       map.forEach((key,val)->{
           System.out.println("城市:"+key+" ---员工集: "+val);
       });
    
  • 方法二、groupingBy(Function,Collector)
    一个参数:一个分组器,使用提供的字段对集合元素进行分组,返回一个Map<字段,相同字段值的元素集>

    /**
    *  groupBy方法2,groupingBy(Function,Collector)
    *
    *  要求:先按city分组 ,再对组里面的成员,统计总销售额
    */
    Map<String, Integer> map = emps.stream().collect(Collectors.groupingBy(Employee::getCity, Collectors.summingInt(Employee::getSales)));
       																//先按city分组                                  再对组里面的成员,统计总销售额
     	map.forEach((key,val)->{
           System.out.println("城市:"+key+" 销售总额:"+val);
       });
    /**
    * groupBy方法2,groupingBy(Function,Collector)
    *
    * 即:获取每个城市的姓氏集
    * 先按城市分组,再对每个组里面的员工姓名放入Set,得到每个城市的姓氏集
    */
    Map<String, Set<String>> map =emps.stream().collect(Collectors.groupingBy(Employee::getCity, Collectors.mapping(Employee::getName, Collectors.toSet())));
        map.forEach((key,val)->{
           System.out.println(""+key+" ---人员姓名: "+val);
       });
      
    /**
    * groupBy方法2,groupingBy(Function,Collector)
    * 要求:每个城市中销售额最大的员工
    *      先按城市分组,在求分组里面销售额最大的员工
    */
    Map<String, Employee> map = emps.stream().collect(Collectors.groupingBy(Employee::getCity,
    Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Employee::getSales)), Optional::get)));
       	map.forEach((key,val)->{
           System.out.println("城市:"+key+" 销售额最大员工:"+val);
       });
    
  • 方法三、groupingBy(Function,Supplier,Collector)
    参数:一个分组器,一个最终类型的生产者,一个收集器
    下面的示例:先按城市分组,然后收集每个城市的姓氏集,然后放入一个TreeMap,得到最终结果。(按城市名称排了序)

     /**
     * 3个参数的方法:groupingBy(Function,Supplier,Collector)
     * 要求:要计算每个城市中人的姓氏集,并对城市名称进行排序
     * 先按城市分组,在对每个城市
     */
    TreeMap<String, Set<String>> map = emps.stream().collect(Collectors.groupingBy(Employee::getCity, TreeMap::new, Collectors.mapping(Employee::getName, Collectors.toSet())));
        map.forEach((key,val)->{
            System.out.println("城市:"+key+" 姓氏集:"+val);
        });
    

三、数组操作:( String [] arr )和 ( Integer [] arrInt )

  • Array>forEach:遍历数组

    Stream.of(arr).forEach(System.out::println);
    
  • Array>distinct+forEach:过滤重复值,遍历集合

    Stream.of(arr).distinct().forEach(x ->{System.out.println("过滤重复值:"+x);});
    
  • Array>limit+forEach:限制输出对象数量,遍历集合

    Stream.of(arr).limit(2).forEach(x ->{System.out.println("限制输出对象:"+x);});
    
  • Array>skip+forEach:跳过n个对象数量,返回集合

    List<String> resu4 = Stream.of(arr).skip(2).collect(Collectors.toList());
    System.out.println("跳过n个对象,返回集合,resu4:"+JSON.toJSONString(resu4));
    
  • Array>allMatch:是否匹配所有元素,返回boolean

    boolean resu8 = Stream.of(arr).allMatch(x -> x.equals("孙悟空"));
    System.out.println("是否匹配所有元素,返回boolean,resu8:"+resu8);
    
  • Array>anyMatch:是否存在元素,返回boolean

    boolean resu9 = Stream.of(arr).anyMatch(x -> x.equals("孙悟空"));
    System.out.println("是否匹配所有元素,返回boolean,resu9:"+resu9);
    
  • Array>noneMatch:是否不存在元素,返回boolean

    boolean resu10 = Stream.of(arr).noneMatch(x -> x.equals("白骨精"));
    System.out.println("是否匹配所有元素,返回boolean,resu10:"+resu10);
    
  • Array>reduce:归约操作,计算总数,返回boolean

    Integer sum = Stream.of(arrInt).reduce(0, Integer::sum);
    System.out.println("计算分数总和,返回总数,sum:"+sum);
    
  • Array>max:查找最大值,返回最大值

    Integer arrMax = Stream.of(arrInt).max(Integer::compareTo).orElse(0);
    System.out.println("查找最大值,返回最大值,arrMax:"+arrMax);
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值