Java8 Stream 使用详解


java8

一、流的定义

  1. Java 8引入了Stream流的概念,它是对集合对象(Collection)进行操作的高级抽象。
  2. Stream流的操作分为两种:中间操作和终端操作。
  3. 中间操作是指在流上进行的操作,返回的仍然是一个流,可以进行链式操作,而终端操作是指对流的最终操作,返回的是一个结果或者一个副作用。
  4. Stream流的特点如下:
  • Stream流是对集合对象的一种封装,使得可以用函数式编程的方式对集合进行操作。
  • Stream流的操作是延迟执行的,只有在终端操作时才会触发执行。
  • Stream流可以进行并行操作,提高了程序的性能。

二、流的创建

1. 通过集合创建流:

可以通过集合类的stream()方法或parallelStream()方法来创建一个流。例如:

List<String> list = Arrays.asList(“a”, “b”, “c”);
Stream<String> stream = list.stream();

2. 通过数组创建流:

可以通过Arrays类的stream()方法来创建一个数组流。例如:

String[] array = {“a”, “b”, “c”};
Stream<String> stream = Arrays.stream(array);

3. 通过Stream.of()创建流:

可以使用Stream类的of()方法来创建一个流。例如:

Stream<String> stream = Stream.of(“a”, “b”, “c”);

4. 通过Stream.generate()创建流:

可以使用Stream类的generate()方法来创建一个无限流,需要提供一个Supplier来生成流中的元素。例如:

Stream<String> stream = Stream.generate(() -> “element”);

5. 通过Stream.iterate()创建流:

可以使用Stream类的iterate()方法来创建一个无限流,需要提供一个初始值和一个UnaryOperator来生成流中的元素。例如:

Stream<Integer> stream = Stream.iterate(0, n -> n + 1);

6. 通过文件、网络、IO流等方式来创建流:

例如:

Stream<String> stream = Files.lines(Paths.get(“file.txt”));
Stream<String> stream = BufferedReader.lines();

这些是Java 8中常用的几种创建流Stream的方式,可以根据具体的需求选择适合的方式来创建流。

三、常用流

1. 中间操作

1.1. filter(Predicate predicate):

根据给定的条件对流进行过滤,只保留满足条件的元素。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamFilterDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 使用filter()方法过滤出偶数
        Stream<Integer> evenNumbersStream = numbers.stream()
                .filter(number -> number % 2 == 0);

        // 打印过滤后的结果
        evenNumbersStream.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个包含整数的列表numbers。然后,我们使用stream()方法将列表转换为流,然后使用filter()方法对流进行过滤,只保留满足条件(即为偶数)的元素。最后,我们使用forEach()方法打印过滤后的结果。

注意:filter()方法返回一个新流,而不会修改原始流。因此,在使用filter()方法后,如果想要继续对流进行其他操作,需要将结果保存到一个新的流中。

1.2. map(Function<T, R> mapper):

将流中的每个元素通过给定的映射函数进行转换。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamMapDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

        // 将名字转换为大写
        List<String> upperCaseNames = names.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());

        // 打印转换后的结果
        upperCaseNames.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个包含字符串的列表names。然后,我们使用stream()方法将列表转换为流,然后使用map()方法对流中的每个元素进行转换,将名字转换为大写。最后,我们使用collect()方法将转换后的结果收集到一个新的列表中,并使用forEach()方法打印结果。

在map()方法中,我们传递了一个方法引用String::toUpperCase,它代表了一个从String类型到String类型的映射函数,将字符串转换为大写字母。map()方法会将流中的每个元素都应用这个映射函数,并返回一个新的流,其中包含了转换后的结果。

注意:map()方法返回一个新流,而不会修改原始流。因此,在使用map()方法后,如果想要继续对流进行其他操作,需要将结果保存到一个新的流中。

1.3. flatMap(Function<T, Stream> mapper):

将流中的每个元素通过给定的映射函数转换为一个新的流,并将所有流合并为一个流。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamFlatMapDemo {
    public static void main(String[] args) {
        List<List<Integer>> numbers = Arrays.asList(
                Arrays.asList(1, 2, 3),
                Arrays.asList(4, 5, 6),
                Arrays.asList(7, 8, 9)
        );

        // 将二维列表转换为一维列表
        List<Integer> flattenedList = numbers.stream()
                .flatMap(List::stream)
                .collect(Collectors.toList());

        // 打印转换后的结果
        flattenedList.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个包含多个列表的二维列表numbers。然后,我们使用stream()方法将二维列表转换为流,然后使用flatMap()方法对流中的每个元素进行转换,将每个列表转换为一个流,并将所有流合并为一个流。最后,我们使用collect()方法将转换后的结果收集到一个新的列表中,并使用forEach()方法打印结果。

在flatMap()方法中,我们传递了一个方法引用List::stream,它代表了一个从List类型到Stream类型的映射函数,将列表转换为流。flatMap()方法会将流中的每个元素都应用这个映射函数,并返回一个新的流,其中包含了转换后的结果。最后,flatMap()方法会将所有的流合并为一个流。

注意:flatMap()方法返回一个新流,而不会修改原始流。因此,在使用flatMap()方法后,如果想要继续对流进行其他操作,需要将结果保存到一个新的流中。

1.4. sorted():

对流进行排序,默认按照元素的自然顺序进行排序。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSortedDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(5, 3, 8, 2, 9, 1);

        // 对流进行排序
        List<Integer> sortedList = numbers.stream()
                .sorted()
                .collect(Collectors.toList());

        // 打印排序后的结果
        sortedList.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个整数列表numbers。然后,我们使用stream()方法将列表转换为流,并使用sorted()方法对流中的元素进行排序。由于没有指定排序规则,所以默认按照元素的自然顺序进行排序。最后,我们使用collect()方法将排序后的结果收集到一个新的列表中,并使用forEach()方法打印结果。

注意:sorted()方法返回一个新流,而不会修改原始流。因此,在使用sorted()方法后,如果想要继续对流进行其他操作,需要将结果保存到一个新的流中。

1.5. distinct():

去除流中的重复元素。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamDistinctDemo {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 4, 3, 5);

        // 去除流中的重复元素
        List<Integer> distinctList = numbers.stream()
                .distinct()
                .collect(Collectors.toList());

        // 打印去重后的结果
        distinctList.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个整数列表numbers,其中包含一些重复的元素。然后,我们使用stream()方法将列表转换为流,并使用distinct()方法去除流中的重复元素。最后,我们使用collect()方法将去重后的结果收集到一个新的列表中,并使用forEach()方法打印结果。

注意:distinct()方法会根据元素的hashCode()和equals()方法来判断元素是否重复。因此,如果要去除流中的自定义对象的重复元素,需要正确实现该对象的hashCode()和equals()方法。

1.6. limit(long maxSize):

限制流的大小,只取前N个元素。

import java.util.stream.Stream;

public class StreamLimitDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的无限流
        Stream<Integer> infiniteStream = Stream.iterate(0, i -> i + 1);

        // 限制流的大小,只取前5个元素
        Stream<Integer> limitedStream = infiniteStream.limit(5);

        // 打印限制后的结果
        limitedStream.forEach(System.out::println);
    }
}

在上面的示例中,我们首先创建了一个包含整数的无限流,使用Stream.iterate()方法从0开始生成整数。然后,我们使用limit()方法限制流的大小,只取前5个元素。最后,我们使用forEach()方法打印限制后的结果。

limit()方法接受一个参数maxSize,表示要限制的大小。它会返回一个新的流,其中包含原始流中的前maxSize个元素。如果原始流的大小小于maxSize,则返回原始流的所有元素。

使用limit()方法可以在处理大量数据时,只取需要的部分数据进行操作,提高程序的性能。

2. 终端操作

2.1. forEach(Consumer action):

对流中的每个元素执行给定的操作。

import java.util.stream.Stream;

public class StreamForEachDemo {
    public static void main(String[] args) {
        // 创建一个包含字符串的流
        Stream<String> stringStream = Stream.of("apple", "banana", "cherry");

        // 对流中的每个元素执行操作
        stringStream.forEach(s -> System.out.println("Fruit: " + s));
    }
}

在上面的示例中,我们首先创建了一个包含字符串的流,使用Stream.of()方法创建一个包含"apple"、"banana"和"cherry"的流。然后,我们使用forEach()方法对流中的每个元素执行操作,即打印出"Fruit: "加上元素的值。

forEach()方法接受一个Consumer接口的实现,用于定义对每个元素的操作。在示例中,我们使用了Lambda表达式来实现Consumer接口,打印出每个水果的名字。

使用forEach()方法可以对流中的每个元素执行任意操作,如打印、计算、过滤等。它是一种简洁、方便的遍历流元素的方式。

2.2. collect(Collector<T, A, R> collector):

将流中的元素收集到一个集合中,可以是List、Set、Map等。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamCollectDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);

        // 将流中的元素收集到List集合中
        List<Integer> numberList = numberStream.collect(Collectors.toList());

        // 打印收集到的List集合
        System.out.println(numberList);
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含1、2、3、4、5的流。然后,我们使用collect()方法将流中的元素收集到List集合中,通过传递Collectors.toList()作为参数,表示将元素收集到一个List集合中。

使用collect()方法可以将流中的元素收集到各种集合中,例如List、Set、Map等。Collectors类提供了许多静态方法,用于创建各种收集器,以满足不同的需求。

你可以根据需要选择适合的收集器,然后将其传递给collect()方法,将流中的元素收集到相应的集合中。

2.3. count():

返回流中的元素个数。

import java.util.stream.Stream;

public class StreamCountDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);

        // 获取流中的元素个数
        long count = numberStream.count();

        // 打印元素个数
        System.out.println("Number of elements: " + count);
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含1、2、3、4、5的流。然后,我们使用count()方法获取流中的元素个数,将结果保存在一个long类型的变量中。

最后,我们打印出元素个数。注意,count()方法返回的是一个long类型的值,表示流中的元素个数。

使用count()方法可以方便地获取流中元素的个数,无需遍历整个流。这对于需要统计元素个数的场景非常有用。

2.4. anyMatch(Predicate predicate):

检查流中是否存在满足给定条件的元素。

import java.util.stream.Stream;

public class StreamAnyMatchDemo {
    public static void main(String[] args) {
        // 创建一个包含字符串的流
        Stream<String> stringStream = Stream.of("apple", "banana", "orange", "grape");

        // 检查流中是否存在长度大于5的元素
        boolean anyMatch = stringStream.anyMatch(s -> s.length() > 5);

        // 打印结果
        if (anyMatch) {
            System.out.println("存在长度大于5的元素");
        } else {
            System.out.println("不存在长度大于5的元素");
        }
    }
}

在上面的示例中,我们首先创建了一个包含字符串的流,使用Stream.of()方法创建一个包含"apple"、“banana”、“orange”、"grape"的流。然后,我们使用anyMatch()方法检查流中是否存在长度大于5的元素,通过Lambda表达式s -> s.length() > 5来定义判断条件。

最后,我们根据anyMatch()方法的返回结果打印出相应的结果。

使用anyMatch()方法可以方便地检查流中是否存在满足给定条件的元素,无需遍历整个流。这对于需要判断某个条件是否成立的场景非常有用。

2.5. allMatch(Predicate predicate):

检查流中的所有元素是否都满足给定条件。

import java.util.stream.Stream;

public class StreamAllMatchDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);

        // 检查流中是否所有元素都大于0
        boolean allMatch = numberStream.allMatch(n -> n > 0);

        // 打印结果
        if (allMatch) {
            System.out.println("所有元素都大于0");
        } else {
            System.out.println("不是所有元素都大于0");
        }
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含1、2、3、4、5的流。然后,我们使用allMatch()方法检查流中是否所有元素都大于0,通过Lambda表达式n -> n > 0来定义判断条件。

最后,我们根据allMatch()方法的返回结果打印出相应的结果。

使用allMatch()方法可以方便地检查流中的所有元素是否都满足给定条件,如果流中的元素个数很大,一旦发现有某个元素不满足条件,就会立即返回false,无需遍历整个流。这对于需要判断所有元素是否满足某个条件的场景非常有用。

2.6. noneMatch(Predicate predicate):

检查流中的所有元素是否都不满足给定条件。

import java.util.stream.Stream;

public class StreamNoneMatchDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);

        // 检查流中是否所有元素都不等于0
        boolean noneMatch = numberStream.noneMatch(n -> n == 0);

        // 打印结果
        if (noneMatch) {
            System.out.println("所有元素都不等于0");
        } else {
            System.out.println("有元素等于0");
        }
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含1、2、3、4、5的流。然后,我们使用noneMatch()方法检查流中是否所有元素都不等于0,通过Lambda表达式n -> n == 0来定义判断条件。

最后,我们根据noneMatch()方法的返回结果打印出相应的结果。

使用noneMatch()方法可以方便地检查流中的所有元素是否都不满足给定条件,如果流中的元素个数很大,一旦发现有某个元素满足条件,就会立即返回false,无需遍历整个流。这对于需要判断所有元素是否都不满足某个条件的场景非常有用。

2.7. reduce(BinaryOperator accumulator):

将流中的元素进行归约操作,返回一个Optional对象。

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

public class StreamReduceDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);

        // 对流中的元素进行求和
        Optional<Integer> sum = numberStream.reduce((a, b) -> a + b);

        // 打印结果
        sum.ifPresent(result -> System.out.println("求和结果为: " + result));
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含1、2、3、4、5的流。然后,我们使用reduce()方法将流中的元素进行求和操作,通过Lambda表达式(a, b) -> a + b来定义求和的规则。

reduce()方法返回一个Optional对象,表示归约操作的结果。我们可以使用ifPresent()方法检查Optional对象是否有值,如果有值则打印出结果。

使用reduce()方法可以对流中的元素进行各种归约操作,如求和、求最大值、求最小值等。根据传入的归约规则,可以对元素进行累积操作,得到一个最终的结果。

2.8. min(Comparator comparator):

返回流中的最小元素。

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

public class StreamMinDemo {
    public static void main(String[] args) {
        // 创建一个包含字符串的流
        Stream<String> stringStream = Stream.of("apple", "banana", "orange", "grape");

        // 找到字典序最小的字符串
        Optional<String> minString = stringStream.min(Comparator.naturalOrder());

        // 打印结果
        minString.ifPresent(result -> System.out.println("最小的字符串为: " + result));
    }
}

在上面的示例中,我们首先创建了一个包含字符串的流,使用Stream.of()方法创建一个包含"apple"、“banana”、“orange”、"grape"的流。然后,我们使用min()方法找到字典序最小的字符串,通过Comparator.naturalOrder()方法指定字符串的比较规则。

min()方法返回一个Optional对象,表示流中的最小元素。我们可以使用ifPresent()方法检查Optional对象是否有值,如果有值则打印出结果。

使用min()方法可以根据指定的比较器找到流中的最小元素。根据比较规则,可以比较不同类型的元素,如整数、字符串等。

2.9. max(Comparator comparator):

返回流中的最大元素。

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

public class StreamMaxDemo {
    public static void main(String[] args) {
        // 创建一个包含整数的流
        Stream<Integer> integerStream = Stream.of(5, 2, 8, 1, 10);

        // 找到最大的整数
        Optional<Integer> maxInteger = integerStream.max(Comparator.naturalOrder());

        // 打印结果
        maxInteger.ifPresent(result -> System.out.println("最大的整数为: " + result));
    }
}

在上面的示例中,我们首先创建了一个包含整数的流,使用Stream.of()方法创建一个包含5、2、8、1、10的流。然后,我们使用max()方法找到最大的整数,通过Comparator.naturalOrder()方法指定整数的比较规则。

max()方法返回一个Optional对象,表示流中的最大元素。我们可以使用ifPresent()方法检查Optional对象是否有值,如果有值则打印出结果。

使用max()方法可以根据指定的比较器找到流中的最大元素。根据比较规则,可以比较不同类型的元素,如整数、字符串等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Run,boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值