JDK8-2-流(2)- 流操作

JDK8-2-流(2)- 流操作

上篇 JDK8-2-流(1)-简介 中简单介绍了什么是流以及使用流的好处,本篇主要介绍流的操作类型以及如何操作。

如何返回一个流

① collection.stream

即调用集合 java.util.Collection 下的 stream 方法

List list = Arrays.asList("a","b","c");
list.stream();

② 数组 Arrays.stream

String[] a = new String[]{"a", "b", "c"};
Arrays.stream(a);

③ Stream.of

String[] b = new String[]{"a", "b", "c"};
Stream.of(b);

这种方式与②类似,它内部也是调用 Arrays.stream 方法

public static Stream of(T... values) {
    return Arrays.stream(values);
}

操作流

以上篇中例子说明:

menu.stream()
    .filter(dish -> dish.getCalories() < 400)
    .sorted(Comparator.comparing(Dish::getCalories))
    .map(Dish::getName)
    .collect(Collectors.toList());

filter,sorted,map 方法称为中间操作,collect 称为终端操作

中间操作

诸如filter或sorted等中间操作会返回另一个流。这让多个操作可以连接起来形成一个查询。重要的是,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。

filter

过滤流中元素,保留需要的元素

Stream filter(Predicate predicate);
.filter(dish -> dish.getCalories() < 400)

map

将类型为 T 的流转换成类型为 R 的流

 Stream map(Function mapper);

例如,将 Dish 类型的流转换成 String 类型的流

List dishNames = menu.stream()
                .map(Dish::getName)
                .collect(Collectors.toList());

distinct

JDK8-2-流(2.1)- 流操作-distinct

sorted

对流中的元素排序

Stream sorted(Comparator comparator);
REPEATED_DISHES.stream()
                .sorted(Comparator.comparing(Dish::getCalories))
                .collect(Collectors.toList());

limit (截断流)

表示截断流中元素,只保留前面 maxSize 个

Stream limit(long maxSize);
List strList = Arrays.asList("a", "b", "c").stream().limit(1).collect(Collectors.toList());
System.out.println(strList);

结果:

[a]

skip (跳过元素)

表示跳过流中前 n 个元素,返回一个扔掉了前n个元素的流,如果流中元素不足n个,则返回一个空流。请注意,limit(n)和skip(n)是互补的!

Stream skip(long n);
List strList2 = Arrays.asList("a", "b", "c").stream().skip(1).collect(Collectors.toList());
System.out.println(strList2);

结果:

[b, c]

假设代码改成如下这样,跳过前 5 个元素,

List strList2 = Arrays.asList("a", "b", "c").stream().skip(5).collect(Collectors.toList());

由于集合中一共只有3个元素,所以结果返回一个空的列表

[]

flatMap (流的扁平化处理)

JDK8-2-流(2.2)- 流操作-flatMap

终端操作

终端操作会从流的流水线生成结果。其结果是任何不是流的值,比如List、Integer,甚至void。

forEach

遍历流中的元素

void forEach(Consumer action);
List str = Arrays.asList("Hello", "World");
str.stream().forEach(s -> System.out.println(s));

结果:

Hello
World

count

统计流中元素个数

long count();
List str = Arrays.asList("Hello", "World");
long length = str.stream().count();
System.out.println(length);

结果:

2

min

筛选出流中最小元素,入参为 Comparator ,返回一个 Optional,关于 Optional 可以参考JDK8-10-Optional(1)

Optional min(Comparator comparator);
List numbers = Arrays.asList(3, 2, 5, 1);
Optional optional = numbers.stream().min((Comparator.comparingInt(o -> o)));
System.out.println(optional.get());

结果:

1

max

和 min 类似,max 表示筛选出流中最大元素,入参为 Comparator ,返回一个 Optional

Optional max(Comparator comparator);
List numbers = Arrays.asList(3, 2, 5, 1);
Optional optional = numbers.stream().max((Comparator.comparingInt(o -> o)));
System.out.println(optional.get());

结果:

5

collect

意为将流的元素转换成集合,主要可以转换成如下三种集合:

  1. Collectors.toList() 转换成 List
  2. Collectors.toSet() 转换成 Set
  3. Collectors.toMap 转换成 Map

Collectors.toList

将字符串列表转换成 Integer 列表

List lenList = Arrays.asList("Hello", "World")
                .stream()
                .map(String::length)
                .collect(Collectors.toList());

Collectors.toSet

将流中元素转换成 Set 集合

Set strList = Arrays.asList("Hello", "World", "Hello")
        .stream()
        .collect(Collectors.toSet());
System.out.println(strList);

结果:

[Hello, World]

Collectors.toMap

将流中元素转换成 Map
如下例:
将 Dish 流中元素转成 key 为 name,value 为 type 的 Map

public static void toMapTest() {
    List dishes = Arrays.asList(
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER));
    Map map = dishes.stream().collect(Collectors.toMap(Dish::getName, d -> d.getType().toString()));
    System.out.println(map);
}

注意:如果程序在转换过程中发现有重复的 key 值,按照上面那种写法会报如下错误:
JDK8-2-流(2)- 流操作_第1张图片
所以需要对 key 去重,如下:

private static  Predicate distinctByKey(Function keyExtractor) {
    Set set = ConcurrentHashMap.newKeySet();
    return t -> set.add(keyExtractor.apply(t));
}

Map map = dishes.stream()
            .filter(distinctByKey(Dish::getName))
            .collect(Collectors.toMap(Dish::getName, d -> d.getType().toString()));

打印结果:

{chicken=MEAT, french fries=OTHER}

allMatch

判断流中的元素是否都匹配某个条件

boolean allMatch(Predicate predicate);

如下,判断数组中数字是否都为偶数:

boolean allNumbersAreEven = Arrays.asList(1, 2, 3)
                .stream()
                .allMatch(a -> a % 2 == 0);
System.out.println(allNumbersAreEven);

结果:

false

anyMatch

判断流中是否有元素满足某个条件

boolean anyMatch(Predicate predicate);

如下,判断数组中数字是否有一个为偶数:

public static void anyMatchTest() {
    boolean allNumbersAreEven = Arrays.asList(1, 2, 3)
            .stream()
            .anyMatch(a -> a % 2 == 0);
    System.out.println(allNumbersAreEven);
}

结果:

true

noneMatch

判断流中元素是不是都不满足条件,如果都不满足则返回 true,否则返回 false

boolean noneMatch(Predicate predicate);

如下,判断数组中数字是否都不是偶数:

public static void noneMatchTest() {
    boolean flag = Arrays.asList(1, 3, 5)
            .stream()
            .noneMatch(a -> a % 2 == 0);
    System.out.println(flag);
}

由于数组中数字都为 奇数 ,而判断条件是偶数,所以数组中没有数字满足条件,所以结果为 true :

true

findAny (查找任意元素)

返回流中任意一个元素的 Optional 包装对象

Optional findAny();
Optional optional = Arrays.asList(1, 2, 3)
        .stream()
        .findAny();
System.out.println(optional.get());

findFirst (查找第一个元素)

返回流中第一个元素的 Optional 包装对象

Optional findFirst();
Optional optional = Arrays.asList(1, 2, 3)
        .stream()
        .findFirst();
System.out.println(optional.get());

reduce (归约)

JDK8-2-流(2.3)- 流操作-reduce (归约)

你可能感兴趣的:(JavaSE,java,开发语言)