示例详解 Stream 流

本文介绍了 Stream API 的常见函数:Collect(收集)、Filter(过滤)、Map(转换)、Sorted(排序)、Distinct(去重)、Limit(限制)、Skip(跳过)、Peek(展示)、forEach(遍历)、Count(计数)、Reduce(聚合)、AnyMatch(任意匹配)、AllMatch(全部匹配)、NoneMatch(没有匹配项)等常见的方法,通过将这些方法搭配使用,可以解决大部分开发问题。

1、Collect(收集)

collect 方法可以将流中的元素收集到一个集合中。一般与其他方法配合使用。这个方法使用频率很高, collect(Collectors.toList()) 是将 stream 流转换成数组。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> list = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
        System.out.println(list);
    }
}

这段代码创建了一个包含整数的列表 numbers,使用流式操作筛选出所有偶数,然后将它们收集到一个新的列表 list 中,并打印输出。

2、Filter(过滤)

filter 方法使用一个结果为 boolean 值的条件对所有元素进行判断,默认结果为 true 的数据可以通过,即结果中只包含判断条件为 true 的数据。

示例:筛选出数组中长度大于 4 的元素。

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("aa", "bbbb", "ccc", "dddddd", "bbbb");
        List<String> collect = names.stream().filter(item -> item.length() > 3).collect(Collectors.toList());
        // filter 用于过滤,后跟过滤条件,可支持多次过滤
    }
}

代码中 names.stream().filter(item -> item.length() > 3) 的结果是一个 Stream<String> 流的 collectcollect(Collectors.toList()) 则将筛选后的结果转换成一个List集合返回。

filter 函数经常搭配一些其他条件或者函数进行使用,例如对数据进行多次过滤并去重:

List<String> collect = names.stream()
		.filter(item -> item.length() > 3)
		.filter(item -> item.length() < 5)
		.distinct()
		.collect(Collectors.toList());

3、Map(转换)

map 方法根据设定好的条件对流中的每一个元素进行转换操作,会根据原数据流生成一个新的数据流。常用作对数组对象中数据的计算或修改操作。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = numbers.stream().map(item -> {
            item = item * 2;
            // 这里需要使用 return,将操作后的结果保存到新的列表中
            return item;
        }).collect(Collectors.toList()); // 返回一个数组对象

		// 使用 toMap 将数字数组 转换成 字节-整数键值对
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 7);
        Map<Byte, Integer> collect = numbers.stream().collect(Collectors
        	.toMap(Integer::byteValue, item -> item * 2, (val1, val2) -> val2));
        for (Map.Entry<Byte, Integer> map : collect.entrySet()) {
            Byte key = map.getKey();
            System.out.println("key = " + key + ", Value = " + map.getValue());
        }
    }
}
  • toMap 方法以每个整数的字节值为键,即 Integer::byteValue
  • 以该整数乘以 2 为值,即 item -> item * 2
  • 当遇到重复的键时取最后一个值,即 (val1, val2) -> val2
  • 要注意 Map 的键要具有唯一性。
  • 调用 collect(Collectors.toMap(…)) 方法转换成 Map<Byte, Integer>

4、Sorted(排序)

sorted 方法是对流的数据按照规则进行排序。可以接受一个 Comparator 参数,也可以使用自然排序 Ordering.natural() 。默认排序是按 升序 排序,即从小到大 。

public class Main {
    public static void main(String[] args) {
        int[] num = { 5, 2, 8, 3, 7 };
        int[] aa = Arrays.stream(num).sorted().toArray();
        System.out.println(Arrays.toString(aa));
        // ----- [2, 3, 5, 7, 8]
        
        String[] bb = {"f", "b", "e", "a", "c", "d"};
        Object cc = Arrays.stream(bb).sorted().toArray();
        System.out.println(Arrays.toString(cc));
        // ----- [a, b, c, d, e, f]
    }
}

代码使用 Arrays.stream() 方法将其转化为一个 IntStream 流。接下来使用 sorted() 方法对流中的元素进行排序,返回一个新的排序后的 IntStream 流。使用 toArray() 方法将排序后的结果转换为一个新的 int 类型数组,并使用 Arrays.toString() 方法将结果打印到控制台。String 类型数组也是同样操作,排序默认是按照升序进行,即从小到大的顺序。

5、Distinct(去重)

distinct 从流中筛选掉相同的元素,去重操作,返回的数据流结果会按照原顺序排列,被删除的位置会被后面的元素依次补齐。使用 equals() 方法来比较元素是否相同,需要确保 equals() 方法实现。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 2, 1, 4, 6, 4, 5);
        List<Integer> collect = numbers.stream().distinct().collect(Collectors.toList());
        System.out.println(collect);
        // [1, 2, 3, 4, 6, 5]
    }
}

6、Limit(限制)

limit 可以将流截取指定的元素数量,例如截取前 3 个元素。这个方法只能从 0 位开始截取,如果需要中间部分的数据,则需要对数组做一定变换操作。例如和下面要讲的 Skip 进行搭配。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = numbers.stream().limit(3).collect(Collectors.toList());
        System.out.println(collect);
        // [1, 2, 3]
        
        List<Integer> collect1 = numbers.stream().skip(1).limit(3).collect(Collectors.toList());
        System.out.println(collect1);
        // [2, 3, 4]
    }
}

7、Skip(跳过)

跳过数组的部分元素,即生成一个不包含被跳过的数组,常用作对数组的中间部分或后半部分的截取,常与 limit 函数进行搭配。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = numbers.stream().skip(2).collect(Collectors.toList());
        System.out.println(collect);
        // [3, 4, 5]
		
		List<Integer> collect1 = numbers.stream().skip(1).limit(3).collect(Collectors.toList());
        System.out.println(collect1);
        // [2, 3, 4]
    }
}

8、Peek(展示)

peek 可以用于在Stream流中获取元素同时执行一些操作,如打印、调试、观察等。通常会与其他的方法联合使用。

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("aaa", "bbb", "ccc", "ddd");
        List<String> list = names.stream()
                .peek(System.out::println)
                .filter(name -> name.startsWith("c"))
                .peek(name -> System.out.println("value: " + name))
                .collect(Collectors.toList());
        System.out.println("-----------------------------------------------------------------");
        System.out.println(list);
        // aaa
        // bbb
        // ccc
        // value: ccc
        // ddd
        // [ccc]
    }
}

9、forEach(遍历)

forEach 方法可将给定的方法应用于流中的每个元素,常用作遍历展示。该方法是一种消费流的方式,不会返回值。

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().forEach(System.out::println);
    }
}

10、Count(计数)

count 方法可以返回流中的元素总数。

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        long count = names.stream().count();
        System.out.println(count);
    }
}

11、Reduce(聚合)

reduce 方法可以将流元素聚合为单个结果。它接受一个 BinaryOperator 参数作为累加器。

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
        System.out.println(sum);
        // Optional[15]
        // 就是将所有数据进行累加
    }
}

12、AnyMatch(任意匹配)

anyMatch 方法提供匹配条件,若含有(指整个数组中某一个元素含有),返回 true

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Bob", "Cire", "David");
        boolean flag = names.stream().anyMatch(name -> name.startsWith("B"));
        System.out.println(flag);   // true
    }
}

使用流式操作检查列表其中是否有任意一个元素以字母 “B” 开头,并将检查结果(布尔值)打印输出。

13、AllMatch(全部匹配)

allMatch 方法提供匹配条件,若含有(指整个数组中所有元素都含有),返回 true

public class Main {
    public static void main(String[] args) {
    	List<String> names = Arrays.asList("Alex", "Bob", "Cire", "David");
        boolean flag = names.stream().allMatch(name -> name.startsWith("B"));
        System.out.println(flag); // false
    }
}

14、NoneMatch(没有匹配项)

noneMatch 方法提供匹配条件,若不含有(指整个数组中所有元素都不含有),返回 true

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Bob", "Cire", "David");
        boolean flag = names.stream().noneMatch(name -> name.startsWith("E"));
        System.out.println(flag); // true
    }
}
  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值