avatar

一条在知识海洋的咸鱼

这个家伙很懒,啥也没有留下😋

  • 首页
  • Linux
  • OCJP
  • Java核心技术卷
  • J2EE相关标准
  • 深入理解Java虚拟机
  • NIO与SOcket编程技术指南
  • Java多线程编程核心技术
  • Redis开发与运维
  • Spring Cloud Alibaba 微服务原理与实践
  • DevOps
  • Docker
  • MySQL必知必会
  • AI自学路线
  • Spring Boot 编程思想(核心篇)
主页 第十三章 迭代和过滤集合
文章

第十三章 迭代和过滤集合

发表于 2021-05-18 更新于 2026-06- 10
作者 Administrator
27~35 分钟 阅读

集合流和过滤器。使用 Streams 和 List 的 forEach 方法进行迭代。使用 lambda 表达式过滤集合。

  • 迭代Foreach
    • Iterable接口中的forEach
    • Stream接口中的forEach
    • Map接口中的forEach
  • 过滤Filtering
    • Collection接口新的默认default方法removeIf
    • filter
  • distinct
  • 总结

迭代Foreach

遍历一个List常用的方法是

  • 使用 for 块
List<String> words = ...
for(int i = 0; i < words.size(); i++) {
    System.out.println(words.get(i));
}
  • 使用迭代器:
List<String> words = ...
for(Iterator<String> it = words.iterator(); it.hasNext();) {
    System.out.println(it.next());
}
  • for-each 循环:
List<String> words = ...
for(String w : words) {
    System.out.println(w);
}

建议的方法是尽可能使用 for-each 循环。前两点可能会发生错误(索引和迭代器变量)

Iterable接口中的forEach

该接口中是默认default方法

  • 利用函数接口的优势,java8添加了另一个基于 for-each 循环的迭代列表选项 foreach 方法
default void forEach(Consumer<? super T> action)

在 Iterable 接口中定义的,所以不仅可以用于 list,而且可以用于该接口的所有实现和子类接口(Collection),比如 Queues、 Sets、 Deques,甚至一些与 sql 相关的异常,比如 SQLException
image.png
image.png
这是一个默认方default法,很多实现类都可以覆盖,主要用于处理并发修改。

words.forEach(new Consumer<String>() {
            @Override
            public void accept(String t) {
                System.out.println(t);
            }
        });
        words.forEach(t -> System.out.println(t));
        words.forEach(System.out::println);
  • 在匿名类或 lambda 表达式中使用final规则。下列代码无效
int max = 0;
words.forEach(t -> {
    // The following line won't compile, you can't modify max
    max = Math.max(max, t.length());
    System.out.println(t);
});

因为lambda和匿名类的堆栈原因,导致出入栈,其所使用的变量必须为final

Stream接口中的forEach

Stream接口中也定义了forEach方法,但不是默认default方法,而是抽象方法

void forEach(Consumer<? super T> action)

image.png
此方法为void,不返回stream,是一个终止操作

        Stream<String> stream = words.stream();
// As an anonymous class
        stream.forEach((new Consumer<String>() {
            @Override
            public void accept(String strings) {
                System.out.println(strings);
            }
        }));
// As a lamba expression
        stream.forEach(t -> System.out.println(t));
        stream.sorted()
                .limit(2)
                .forEach(System.out::println);
// As a method reference
        stream.forEach(System.out::println);
  • stream流的又是在于可以进行连锁操作
  • 如果使用stream的终止操作,则stream流会被销毁
    image.png
    所以使用stream流的forEach后就不能在使用,会提示已经被操作或关闭,抛出异常
  • 如果在终止操作后想重新使用stream流则必须重新创建一个新的流
Stream.of(wordList).forEach(t -> System.out.println(t.length()));
Stream.of(wordList).forEach(System.out::println);
  • 或者将需要调用的方法包装到一个lambda表达式中
Consumer<String> print = t -> {
    System.out.println(t.length());
    System.out.println(t);
};
words.forEach(print);
  • 不能使用 return、 break 或 continue 来终止迭代。
    break、continue不能在循环之外使用,会产生编译错误。
    return因为在方法体内,所以不会有影响

Map接口中的forEach

在JDK1.8中Map接口新增的默认default方法。因为Map接口中含有K-V,所以该方法需要BiConsumer接口
image.png

  • 源码
default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

其等价于增强for循环

for (Map.Entry<K, V> entry : map.entrySet()) {
    action.accept(entry.getKey(), entry.getValue());
}

过滤Filtering

从集合中筛选(或删除)与特定条件不匹配的元素

  • 将匹配的元素复制到另一个集合来实现
List<String> words = Arrays.asList("a","b",null) ;
        List<String> nonEmptyWords = new ArrayList<String>();
        for(String w : words) {
            if(w != null && !w.isEmpty()) {
                nonEmptyWords.add(w);
            }
        }
        System.out.println(nonEmptyWords);
  • 使用迭代器删除集合本身中的不匹配元素(仅当集合支持删除时)
for (Iterator<String> it = words.iterator(); it.hasNext(); ) {
            String w = it.next();
            if (w == null || w.isEmpty()) {
                it.remove();
            }
        }

image.png
因为word1的ArrayList是Arrays的内部类,其没有重写Iterator接口的默认remove方法会抛出异常
image.png
而正统的ArrayList重写了remove方法
image.png

Collection接口新的默认default方法removeIf

default boolean removeIf(Predicate<? super E> filter)

image.png

  • 匿名内部类
words.removeIf(new Predicate<String>() {
            @Override
            public boolean test(String t) {
                return t == null || t.isEmpty();
            }
        });
  • lambda表达式
words.removeIf(t -> t == null || t.isEmpty());

filter

将匹配元素复制到另一个集合可以使用Stream接口filter方法

Stream<T> filter(Predicate<? super T> predicate)

因为这个方法返回一个流,它表示一个中间操作,这基本上意味着你可以链接任意数量的过滤器或者其他中间操作
image.png

List<String> words = Arrays.asList("hello", null, "");
words.stream()
    .filter(t -> t != null) // ["hello", ""]
    .filter(t -> !t.isEmpty()) // ["hello"]
    .forEach(System.out::println);
  • 可以在某个类上创建一个方法(或者使用一个现有的方法) ,通过一个方法引用来实现
        List<String> words2 = Arrays.asList("hello", null, "");
// Using an anonymous class
        words2.stream()
                .filter(new Predicate<String> () {
                    @Override
                    public boolean test(String t) {
                        return StringUtils.isNotNullOrEmpty(t);
                    }
                })
                .forEach(System.out::println);
// Using a lambda expression
        words2.stream()
                .filter(t -> StringUtils.isNotNullOrEmpty(t))
                .forEach(System.out::println);
// Using a lambda expression
        words2.stream()
                .filter(StringUtils::isNotNullOrEmpty)
                .forEach(System.out::println);
    }
}
class StringUtils {
    public static boolean isNotNullOrEmpty(String s) {
        return s != null && !s.isEmpty();
    }
}

distinct

根据 Object.equals(Object)方法,Stream 接口还具有过滤重复元素的独特方法

Stream<T> distinct()

它返回一个新的流,所以这是一个中间操作。
它必须知道元素的值以找出哪些是重复的,所以这个操作也是有状态的

总结

  • foreach迭代
    1.Iterable接口
    Java8将以下方法添加到Iterable接口中
    default void forEach(Consumer<? super T> action)
    2.Stream接口
    Stream 也有该方法为abstract
    void forEach(Consumer<? super T> action)
    这是一个终止操作
  • filter集合过滤
    1.collection接口
    default boolean removeIf(Predicate<? super E> filter)
    移除集合中满足给定谓词的所有元素
    2.Stream接口
    Stream filter(Predicate<? super T> predicate)
    此方法返回流,中间操作,可以链接任意数量的筛选器或其他中间操作
  • distinct去重
    1.Stream接口
    Stream distinct()
    中间操作,因为它必须知道元素的值才能找出哪些元素是重复的,所以这个操作也是有状态的
OCJP
许可协议: 
分享

相关文章

9月 6, 2021

关于这篇OCP-Java专题说明

5月 28, 2021

三十章 本地化

通过使用 Locale 对象读取和设置 Locale。创建并读取属性文件。为每个区域设置构建资源包,并在应用程序中加载资源包。本地化设置语言环境本地化设计一个能够处理不同语言和地区的应用程序。最常见的是消息、日期和数字。java.util.LocaleLocale类基本上代表一种语言和一个国家获得机

5月 27, 2021

第二十九章 JDBC API

了解JDBC API 核心的接口,包括 Driver、 Connection、 Statement 和 ResultSet 接口及其与提供者实现的关系。使用 DriverManager 类(包括 JDBC URL)标识连接到数据库所需的组件。从数据库提交查询和读取结果,包括创建语句、返回结果集、遍历

下一篇

第十四章 Optional类

上一篇

第十二章 Stream流

最近更新

  • 55 异常兜底:工具失败、非法输出、空检索与超时
  • 54 Agent Memory:短期记忆、用户上下文与摘要
  • 53 Human-in-the-loop:让关键动作暂停、确认与恢复
  • 52 工单 Tool:字段校验、创建结果与失败补偿
  • 51 订单 Tool:Mock、鉴权、状态解析与脱敏

热门标签

java基础 微服务 maven Spring Tomcat DDD Linux Linux基础 SQL基础 数据结构算法

目录

©2026 一条在知识海洋的咸鱼. 保留部分权利。

使用 Halo 主题 Chirpy