Java 8 Stream 操作详解

1.Lambda表达式的简化

1.1-指向静态方法的方法引用

/**
* 指向静态方法的方法引用
* (args) -> ClassName.staticMethod(args)
* ClassName::staticMethod; */
@Test
public void test1(){
Consumer<String> consumer=new Consumer<String>() {
@Override
public void accept(String s) {
Integer.parseInt(s);
}
};
Consumer<String> consumer1= s -> Integer.parseInt(s);
Consumer<String> consumer2= Integer::parseInt;
}
​

1.2-指向任意类型实例方法的方法引用

​
/**
* 指向任意类型实例方法的方法引用
* (args) -> args.instanceMethod()
* ClassName::instanceMethod;
* */
@Test
public void test2(){
Consumer<String> consumer1= s -> s.length();
Consumer<String> consumer2=String::length;
}

1.3-指向现有对象的实例方法的方法引用

​
/**
* 指向现有对象的实例方法的方法引用
* (args) -> object.instanceMethod(args)
* object::instanceMethod */
@Test
public void test3(){
StringBuilder stringBuilder=new StringBuilder();
Consumer<String> consumer1= s -> stringBuilder.append(s);
Consumer<String> consumer2= stringBuilder::append;
}

2.Stream流概念

package java.util.stream;
​
Java 8 API添加了一个新的抽象称为流Stream , 可以让你以一种声明的方式处理数据
​
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达 的高阶抽象
Stream API可以极大提高Java程序员的生产力 , 让程序员写出高效率、干净、简洁的代码
​
这种风格将要处理的元素集合看作一种流 , 流在管道中传输 , 并且可以在管道的节点上进行处理 , 比如筛选 , 排序 , 聚合等
元素流在管道中经过中间操作(intermediate operation)的处理 , 最后由最终操作(terminal operation)得到前面处理的结果

3.IDEA匿名内部类与Stream转换

使用场景:
如果匿名内部类是一个接口,并且当中只有一个抽象方法需要重写,可以使用Lambda表达式。
​
匿名内部类转成lambda:
    将鼠标放到内部类对象上然后按下Alt+enter,会提示Replace with lambda
lambda转成匿名内部类:
    将鼠标放到lambda表达式上然后按下Alt+enter,然后选择提示Split into declaration and assignment

4.Stream流与集合的区别

// 对集合遍历都是通过Iterator或者For-Each的方式 , 显式的在集合外部进行迭代 , 这叫做外部迭代 // Stream提供了内部迭代的方式 , 通过访问者模式(Visitor)实现 ( 只能遍历一次 )
集合相当于空间维度的存储 , Stream流相当于时间维度的存储
集合面向的是存储 , Stream流面向的是计算

5.流的组成与分类

// 1. 数据源
​
// 2. 中间操作: 主要是做业务处理( 过滤 , 排序 )
无状态: 无状态操作执行完一个元素就走到下面的状态 , 不需要操作完所有的数据
有状态: 有状态的中间操作要等到上一个状态所有的数据都操作完 , 再统一的进行操作
​
// 3. 终端操作: 对流数据的一个收集 , 形成一个新的数据结构
短路: 只要找到符合条件的第一个数据 , 那么后面的元素就都不会去执行了
非短路: 数据集有多少个数据 , 就要执行多少次操作

6.创建Stream流

6.1-由数值直接构建流

/**
* 1    由数值直接构建流
*/
@Test
public void streamFormValue(){
Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50);
stream.forEach(integer -> System.out.println(integer));
}
​

6.2-通过文件生成流

/**
* 2    通过文件生成流
*/
@Test
public void streamFormFile() throws IOException {
// TODO 此处替换为本地文件的地址全路径
String filePath = "";
​
// import java.nio.file.Files;
// import java.nio.file.Paths;
Stream<String> lines = Files.lines(Paths.get(filePath));
lines.forEach(s -> System.out.println(s));
}

6.3-通过数组构建流

/**
* 3    通过数组构建流
*/
@Test
public void streamForArray(){
int[] arrs={1,2,3,4,5};
IntStream stream = Arrays.stream(arrs);
stream.forEach(i-> System.out.println(i));
}

6.4-通过集合构建流

/**
* 4    通过集合构建流
*          Collection 单列集合体系下的 都有 stream()
*          ! ! !  Map 双列集合体系不能直接构建流 可以转成单列集合 再调用 stream() */
@Test
public void streamForCollection(){
Collection<Integer> collection=new ArrayList<>();
Collections.addAll(collection,1,2,3,4,5);
​
Stream<Integer> stream = collection.stream();
stream.forEach(i-> System.out.println(i));
}

6.5-通过函数生成流 (无限流)

/**
* 5 通过函数生成流 (无限流)
*/
@Test
public void streamForFunction(){
// 第一种
/*Stream<Integer> stream = Stream.iterate(0, new UnaryOperator<Integer>
() {
@Override
public Integer apply(Integer integer) {
return integer + 2;
}
});
stream.forEach(i-> System.out.println(i));*/
​
//第二种
Stream<Integer> stream = Stream.generate(new Supplier<Integer>() { @Override
public Integer get() {
return new Random().nextInt(100) + 1;
}
});
stream.limit(100).forEach(i-> System.out.println(i));
}

7.中间常用方法

无状态

7.1-filter (过滤)

        List<String> strings = Arrays.asList("foo", "bar", "baz", "qux"); 
        // 使用 filter 方法过滤符合条件的元素
        List<String> filtered = strings.stream()
            .filter(s -> s.startsWith("b"))
            .collect(Collectors.toList());
        // 输出过滤后的结果
        System.out.println(filtered); // 输出 [bar, baz]
        
# List自带的removeIf同样可以实现filter的功能
​
       List<String> strings = new ArrayList<>(Arrays.asList("foo", "bar", "baz", "qux")); 
        // 使用 removeIf 方法删除以字母 b 开头的元素
        strings.removeIf(s -> s.startsWith("b"));
        // 输出删除后的结果
        System.out.println(strings); // 输出 [foo, qux]
        
# removeIf与filter区别
removeIf 和 filter 都是流或集合中常用的元素过滤方法,它们之间的区别在于:
removeIf 方法是用于删除集合中符合条件的元素,而 filter 方法只是将符合条件的元素留下来,并生成一个新的流。
removeIf 方法会实际地修改原始集合,而 filter 方法则不会。filter 方法只是生成一个新的流,而不修改原始流或集合。
removeIf 方法适用于对集合进行修改或删除操作,而 filter 方法适用于仅选择符合条件的元素的场景。
因此,如果您需要删除集合中符合条件的元素,则应使用 removeIf 方法。如果您只需要选择符合条件的元素并创建一个新的流或集合,则应使用 filter 方法

7.2-map (映射)

       List<String> strings = Arrays.asList("foo", "bar", "baz", "qux");   
        // 使用 map 方法将字符串转换为大写字母
        List<String> capitalized = strings.stream()
            .map(String::toUpperCase)
            .collect(Collectors.toList());
        // 输出映射后的结果
        System.out.println(capitalized); // 输出 [FOO, BAR, BAZ, QUX]

7.3-flatMap (扁平化)

// 嵌套集合或多维数组的场景
List<List<Integer>> numbers = Arrays.asList(
            Arrays.asList(1, 2),
            Arrays.asList(3, 4),
            Arrays.asList(5, 6)
        );
        
        // 使用 flatMap 方法将多个列表扁平化为一维列表
        List<Integer> flattened = numbers.stream()
            .flatMap(List::stream)
            .collect(Collectors.toList());
        
        // 输出扁平化后的结果
        System.out.println(flattened); // 输出 [1, 2, 3, 4, 5, 6]

7.4-peek (遍历)

      // 调试或日志场景
      int sum = Arrays.stream(new int[] {1, 2, 3, 4, 5})
                .peek(System.out::println)
                .sum();
​
        System.out.println("Sum: " + sum);

有状态

7.5-distinct (去重)

 List<String> strings = Arrays.asList("foo", "bar", "baz", "bar", "qux", "foo");
        
        // 使用 distinct 方法去除重复元素
        List<String> uniqueStrings = strings.stream()
            .distinct()
            .collect(Collectors.toList());
        
        // 输出去重后的结果
        System.out.println(uniqueStrings); // 输出 [foo, bar, baz, qux]

7.6-skip (跳过)

 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        // 使用 skip 方法跳过前三个元素
        List<Integer> skippedNumbers = numbers.stream()
            .skip(3)
            .collect(Collectors.toList());
        
        // 输出跳过后的结果
        System.out.println(skippedNumbers); // 输出 [4, 5]

7.7-limit (截断)

 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        // 使用 limit 方法只保留前三个元素
        List<Integer> limitedNumbers = numbers.stream()
            .limit(3)
            .collect(Collectors.toList());
        
        // 输出截断后的结果
        System.out.println(limitedNumbers); // 输出 [1, 2, 3]

7.8-sorted (排序)

        List<Student> students = Arrays.asList(
            new Student("Alice", 70),
            new Student("Bob", 90),
            new Student("Charlie", 80)
        );
        
        // 使用 sorted 方法根据成绩字段进行排序
        List<Student> sortedStudents = students.stream()
            .sorted(Comparator.comparing(Student::getScore))
            .collect(Collectors.toList());
        
        // 输出排序后的结果
        System.out.println(sortedStudents); // 输出 [Student{name='Alice', score=70}, Student{name='Charlie', score=80}, Student{name='Bob', score=90}]

8.终端操作常用方法

短路操作

8.1-allMatch (所有匹配)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
System.out.println(allEven); // false

8.2-anyMatch (任意匹配)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
System.out.println(hasEven); // true
​

8.3-noneMatch(不匹配)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);
System.out.println(noneNegative); // true
​

8.4-findFirst (查找首个)

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
Optional<String> firstWord = words.stream().findFirst();
if (firstWord.isPresent()) {
    System.out.println(firstWord.get()); // "apple"
}
​

8.5-findAny (查找任意)

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
Optional<String> anyWord = words.stream().findAny();
if (anyWord.isPresent()) {
    System.out.println(anyWord.get()); // 可能会输出 "apple" 或其他字符串
}

非短路操作

8.6-forEach (遍历)

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
words.stream().forEach(word -> System.out.println(word.toUpperCase()));
​

8.7-max (最大值)

List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1"));
​
BigDecimal maxDecimal = decimalList.stream()
        .max(BigDecimal::compareTo)
        .orElse(BigDecimal.ZERO);
​
System.out.println("Maximum decimal: " + maxDecimal);
​

8.8-min (最小值)

List<BigDecimal> list = Arrays.asList(BigDecimal.valueOf(10), 
                                      BigDecimal.valueOf(20), 
                                      BigDecimal.valueOf(5));
BigDecimal min = list.stream()
                     .min(BigDecimal::compareTo)
                     .orElse(BigDecimal.ZERO);

8.9-count (计数)

List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1"));
​
long count = decimalList.stream().count();
​
System.out.println("Number of decimals: " + count);
​

8.10-sum (求和)

List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1"));
​
BigDecimal sum = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
​
System.out.println("Sum of decimals: " + sum);

8.11-avg (平均值)

List<BigDecimal> decimalList = Arrays.asList(new BigDecimal("10.5"), new BigDecimal("8.2"), new BigDecimal("25.1"));
​
OptionalDouble average = decimalList.stream()
        .mapToDouble(BigDecimal::doubleValue)
        .average();
​
if (average.isPresent()) {
    System.out.println("Average of decimals: " + BigDecimal.valueOf(average.getAsDouble()));
} else {
    System.out.println("BigDecimal list is empty");
}

9.Collectors 收集器

9.1-集合收集器

收集器的作用就是将流中的元素累积成一个结果,作用于终端操作。 Collectors 是一个工具类 , 它帮我们提前封装好了一些实现了Collector接口的收集器 , 我们可以直接 拿过来用:

toList()方法:将流中的元素收集到一个List中。

Map<Integer, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));

toSet() 方法:将流中的元素收集到一个 Set 中。

Set<String> set = stream.collect(Collectors.toSet());
​

toMap() 方法:将流中的元素收集到一个 Map 中。可以指定键和值的映射关系。

Collectors.toMap() 方法接受三个参数,用于指定生成 Map 对象的键和值。这三个参数分别是:

  1. 键选择器(key mapper):用于指定如何从元素中提取 Map 的键(即 key)。可以使用 Lambda 表达式、方法引用或者 Function 接口实现来指定。

  2. 值选择器(value mapper):用于指定如何从元素中提取 Map 的值(即 value)。同样可以使用 Lambda 表达式、方法引用或者 Function 接口实现来指定。

  3. 合并函数(merge function):用于处理重复键的情况。当遇到重复键时,应该将两个值合并成一个。可以使用 Lambda 表达式、方法引用或者 BinaryOperator 接口实现来指定。如果省略,则会抛出 IllegalStateException 异常。

List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 20),
        new Person("Alice", 35)
);
​
Map<String, Integer> ageByName = persons.stream()
        .collect(Collectors.toMap(Person::getName, Person::getAge, Math::max));
​
System.out.println(ageByName);
​

9.2-分组

/**
* 分组  根据Sku的类别分组
*/
@Test
public void toGroup(){
Map<Object, List<Sku>> resultMap = list.stream().collect(Collectors.groupingBy(sku-> sku.getSkuCategory()));
System.out.println(JSON.toJSONString(resultMap,true));
}

9.3-分区

/**
* 分区 根据sku的总价分区
* 大于100的为true 单独为一区
* 小于100的为false 单独为一区 */
@Test
public void toPartition(){
Map<Boolean, List<Sku>> collect = list.stream()
.collect(Collectors.partitioningBy(sku -> sku.getTotalPrice() >
100));
​
System.out.println(JSON.toJSONString(collect,true));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值