当前位置: 首页 > article >正文

【Java 集合】Collections 空列表细节处理

问题

如下代码,虽然定义为非空 NonNull,但依然会返回空对象,导致调用侧被检测为空引用。

实际上不是Collections的问题是三目运算符返回了null对象。

import java.util.Collections;

    @NonNull
    private List<String> getInfo() {
        IccRecords iccRecords = mPhone.getIccRecords();
        
        if(iccRecords != null) {
            //省略逻辑
            String[] simSpdi = iccRecords.getServiceProviderDisplayInformation();
            return simSpdi != null ? Arrays.asList(simSpdi) : null; //根因是这里返回null
        }
        return Collections.EMPTY_LIST;
    }

源码案例

frameworks/opt/telephony/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java

    @NonNull
    private List<String> getEfSpdi() {
        for (int i = 0; i < mEf.size(); i++) {
            if (mEf.valueAt(i).getServiceProviderDisplayInformation() != null) {
                return mEf.valueAt(i).getServiceProviderDisplayInformation();
            }
        }
        return Collections.EMPTY_LIST;
    }

    @NonNull
    private String getEfSpn() {
        for (int i = 0; i < mEf.size(); i++) {
            if (!TextUtils.isEmpty(mEf.valueAt(i).getServiceProviderName())) {
                return mEf.valueAt(i).getServiceProviderName();
            }
        }
        return "";
    }

    @NonNull
    private List<OperatorPlmnInfo> getEfOpl() {
        for (int i = 0; i < mEf.size(); i++) {
            if (mEf.valueAt(i).getOperatorPlmnList() != null) {
                return mEf.valueAt(i).getOperatorPlmnList();
            }
        }
        return Collections.EMPTY_LIST;
    }

    @NonNull
    private List<PlmnNetworkName> getEfPnn() {
        for (int i = 0; i < mEf.size(); i++) {
            if (mEf.valueAt(i).getPlmnNetworkNameList() != null) {
                return mEf.valueAt(i).getPlmnNetworkNameList();
            }
        }
        return Collections.EMPTY_LIST;
    }

代码解析

注意Collection和Collections是不同的。

  • libcore/ojluni/src/main/java/java/util/Collections.java 工具类
  • libcore/ojluni/src/main/java/java/util/Collection.java 接口

Collections中定义了内部类EmptyList,在静态List常量EMPTY_LIST(immutable不可变列表)初始化时会new一个没有指定类型的EmptyList。

public class Collections {
    /**
     * The empty list (immutable).  This list is serializable.
     *
     * @see #emptyList()
     */
    @SuppressWarnings("rawtypes")
    public static final List EMPTY_LIST = new EmptyList<>();

    /**
     * Returns an empty list (immutable).  This list is serializable.
     *
     * <p>This example illustrates the type-safe way to obtain an empty list:
     * <pre>
     *     List&lt;String&gt; s = Collections.emptyList();
     * </pre>
     *
     * @implNote
     * Implementations of this method need not create a separate {@code List}
     * object for each call.   Using this method is likely to have comparable
     * cost to using the like-named field.  (Unlike this method, the field does
     * not provide type safety.)
     *
     * @param <T> type of elements, if there were any, in the list
     * @return an empty immutable list
     *
     * @see #EMPTY_LIST
     * @since 1.5
     */
    @SuppressWarnings("unchecked")
    public static final <T> List<T> emptyList() {
        return (List<T>) EMPTY_LIST;
    }

    /**
     * @serial include
     */
    private static class EmptyList<E>
        extends AbstractList<E>
        implements RandomAccess, Serializable {
        @java.io.Serial
        private static final long serialVersionUID = 8842843931221139166L;

        public Iterator<E> iterator() {
            return emptyIterator();
        }
        public ListIterator<E> listIterator() {
            return emptyListIterator();
        }

        // Preserves singleton property
        @java.io.Serial
        private Object readResolve() {
            return EMPTY_LIST;
        }
    }

}

解决方案

将 Collections.EMPTY_LIST 替换成 Collections.emptyList()。

虽然它们都可以用于表示一个空的不可变列表,但 Collections.emptyList() 是更优先的选择,因为它提供了类型安全性和更好的代码可读性。

附:Collections 源码

一些值得学习的语法,Android 扩展的排序跟Java 集合原生排序的实现差异

libcore/ojluni/src/main/java/java/util/Collections.java

import dalvik.system.VMRuntime;

/**
 * This class consists exclusively of static methods that operate on or return
 * collections.  It contains polymorphic algorithms that operate on
 * collections, "wrappers", which return a new collection backed by a
 * specified collection, and a few other odds and ends.
 *
 * <p>The methods of this class all throw a {@code NullPointerException}
 * if the collections or class objects provided to them are null.
 *
 * <p>The documentation for the polymorphic algorithms contained in this class
 * generally includes a brief description of the <i>implementation</i>.  Such
 * descriptions should be regarded as <i>implementation notes</i>, rather than
 * parts of the <i>specification</i>.  Implementors should feel free to
 * substitute other algorithms, so long as the specification itself is adhered
 * to.  (For example, the algorithm used by {@code sort} does not have to be
 * a mergesort, but it does have to be <i>stable</i>.)
 *
 * <p>The "destructive" algorithms contained in this class, that is, the
 * algorithms that modify the collection on which they operate, are specified
 * to throw {@code UnsupportedOperationException} if the collection does not
 * support the appropriate mutation primitive(s), such as the {@code set}
 * method.  These algorithms may, but are not required to, throw this
 * exception if an invocation would have no effect on the collection.  For
 * example, invoking the {@code sort} method on an unmodifiable list that is
 * already sorted may or may not throw {@code UnsupportedOperationException}.
 *
 * <p>This class is a member of the
 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
 * Java Collections Framework</a>.
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see     Collection
 * @see     Set
 * @see     List
 * @see     Map
 * @since   1.2
 */

public class Collections {
    // Suppresses default constructor, ensuring non-instantiability.
    private Collections() {
    }

    // Algorithms

    // Android-added: List.sort() vs. Collections.sort() app compat.
    // Added a warning in the documentation.
    // Collections.sort() calls List.sort() for apps targeting API version >= 26
    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
    /**
     * Sorts the specified list into ascending order, according to the
     * {@linkplain Comparable natural ordering} of its elements.
     * All elements in the list must implement the {@link Comparable}
     * interface.  Furthermore, all elements in the list must be
     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
     * must not throw a {@code ClassCastException} for any elements
     * {@code e1} and {@code e2} in the list).
     *
     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
     * not be reordered as a result of the sort.
     *
     * <p>The specified list must be modifiable, but need not be resizable.
     *
     * @implNote
     * This implementation defers to the {@link List#sort(Comparator)}
     * method using the specified list and a {@code null} comparator.
     * Do not call this method from {@code List.sort()} since that can lead
     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
     * backwards compatibility behavior where this method was implemented
     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
     * {@link ListIterator#set(Object)}.
     *
     * @param  <T> the class of the objects in the list
     * @param  list the list to be sorted.
     * @throws ClassCastException if the list contains elements that are not
     *         <i>mutually comparable</i> (for example, strings and integers).
     * @throws UnsupportedOperationException if the specified list's
     *         list-iterator does not support the {@code set} operation.
     * @throws IllegalArgumentException (optional) if the implementation
     *         detects that the natural ordering of the list elements is
     *         found to violate the {@link Comparable} contract
     * @see List#sort(Comparator)
     */
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        // Android-changed: List.sort() vs. Collections.sort() app compat.
        // Call sort(list, null) here to be consistent with that method's
        // (changed on Android) behavior.
        // list.sort(null);
        sort(list, null);
    }


}

http://www.kler.cn/a/400078.html

相关文章:

  • Go语言基本类型转换
  • 【MySql】实验十六 综合练习:图书管理系统数据库结构
  • 2、计算机网络七层封包和解包的过程
  • 微博短链接平台-项目测试用例设计(Xmind)
  • 第六节、Docker 方式部署指南 github 上项目 mkdocs-material
  • FPGA开发-逻辑分析仪的应用-数字频率计的设计
  • Spark_写ORALCE:ORA-01426 numeric overflow 问题解决
  • 在 Qt 中使用 OpenGL 详解
  • 动态规划入门(记忆化搜索)——爬楼梯(Leetcode 70题)
  • 【WPF】Prism学习(六)
  • PgSQL即时编译JIT | 第1期 | JIT初识
  • 【C++之STL】摸清 string 的模拟实现(上)
  • PlantUML——时序图
  • Python实现ARIMA模型
  • 如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
  • vue项目PC端和移动端实现在线预览docx、excel、pdf文件
  • 配置Nginx实现用IP测试灰度发,通过不同用户ID测试灰度发布
  • Flutter踩坑:原生安卓页面向Flutter通信
  • android通过广播设置默认启动器
  • 【Pikachu】XML外部实体注入实战
  • Loopy为何成为IP联名新顶流,如何赋能品牌营销新高度?
  • 用Ruby编写一个自动化测试脚本,验证网站登录功能的正确性。
  • TCP/IP协议浅析
  • 前端三大件之CSS
  • opencv调整图片对比度和亮度
  • 大模型(LLMs)推理面