You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK17下如何强制方法仅接收不可变List作为参数?

JDK17下强制方法参数为不可变List的实现方式

因为你没法直接用Guava的ImmutableList,这里给你几个可行的方案:

方法一:运行时校验,拒绝可变List

在方法开头加校验逻辑,确保传入的List是不可变的。可以通过尝试执行修改操作(比如add null)来判断——不可变List执行修改会抛出UnsupportedOperationException,如果是List.of()创建的不允许null的不可变List,会抛NullPointerException,这两种情况都说明是不可变集合。

代码示例:

public String topRankingStudentName(List<Student> students) {
    try {
        students.add(null);
        // 能走到这里说明是可变List,直接抛异常
        throw new IllegalArgumentException("必须传入不可变List,请用List.of()或Collections.unmodifiableList()创建");
    } catch (UnsupportedOperationException | NullPointerException e) {
        // 是不可变集合,继续执行业务逻辑
    }

    return students.stream()
            .min(Comparator.comparingInt(Student::rank))
            .map(Student::name)
            .orElse(null);
}

也可以直接判断List的类名是否属于JDK内部的不可变集合实现(比如java.util.ImmutableCollections开头的类),但这种方式依赖JDK内部实现,版本变更可能失效,不如上面的通用。

方法二:自定义不可变List包装类,编译时强制

自己写一个不可变的List包装类,把方法参数类型改成这个自定义类,调用者必须将集合转换成该类型才能传入,从编译层面强制不可变性。

先写包装类:

public final class ImmutableListWrapper<T> implements List<T> {
    private final List<T> delegate;

    private ImmutableListWrapper(List<T> delegate) {
        // 内部直接转成JDK原生不可变List,确保底层不可变
        this.delegate = List.copyOf(delegate);
    }

    // 只实现所有只读方法
    @Override
    public int size() { return delegate.size(); }
    @Override
    public boolean isEmpty() { return delegate.isEmpty(); }
    @Override
    public boolean contains(Object o) { return delegate.contains(o); }
    @Override
    public Iterator<T> iterator() { return Collections.unmodifiableIterator(delegate.iterator()); }
    @Override
    public Object[] toArray() { return delegate.toArray(); }
    @Override
    public <T1> T1[] toArray(T1[] a) { return delegate.toArray(a); }
    @Override
    public boolean containsAll(Collection<?> c) { return delegate.containsAll(c); }
    @Override
    public T get(int index) { return delegate.get(index); }
    @Override
    public int indexOf(Object o) { return delegate.indexOf(o); }
    @Override
    public int lastIndexOf(Object o) { return delegate.lastIndexOf(o); }
    @Override
    public ListIterator<T> listIterator() { return Collections.unmodifiableListIterator(delegate.listIterator()); }
    @Override
    public ListIterator<T> listIterator(int index) { return Collections.unmodifiableListIterator(delegate.listIterator(index)); }
    @Override
    public List<T> subList(int fromIndex, int toIndex) { return new ImmutableListWrapper<>(delegate.subList(fromIndex, toIndex)); }

    // 所有修改方法直接抛异常
    @Override
    public boolean add(T t) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public boolean remove(Object o) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public boolean addAll(Collection<? extends T> c) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public boolean addAll(int index, Collection<? extends T> c) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public void clear() { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public T set(int index, T element) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public void add(int index, T element) { throw new UnsupportedOperationException("不可变List不支持修改"); }
    @Override
    public T remove(int index) { throw new UnsupportedOperationException("不可变List不支持修改"); }

    // 静态工厂方法,供外部创建实例
    public static <T> ImmutableListWrapper<T> of(List<T> list) {
        return new ImmutableListWrapper<>(list);
    }
}

然后修改你的方法签名:

public String topRankingStudentName(ImmutableListWrapper<Student> students) {
    return students.stream()
            .min(Comparator.comparingInt(Student::rank))
            .map(Student::name)
            .orElse(null);
}

调用的时候必须这样传:

List<Student> studentList = List.of(new Student("张三", 1, "一中", "东区"), new Student("李四", 2, "二中", "西区"));
ImmutableListWrapper<Student> immutableList = ImmutableListWrapper.of(studentList);
String topName = topRankingStudentName(immutableList);

这样调用者没办法直接传可变List,必须转成你的不可变包装类,从编译阶段就限制了。

方法三:方法内部创建不可变副本(无需强制调用者,但自身安全)

如果不需要强制调用者传入不可变集合,只是想保证方法内部操作的是不可变的,直接在方法开头用List.copyOf()把传入的List转成不可变副本就行:

public String topRankingStudentName(List<Student> students) {
    List<Student> immutableStudents = List.copyOf(students);
    return immutableStudents.stream()
            .min(Comparator.comparingInt(Student::rank))
            .map(Student::name)
            .orElse(null);
}

这种方式最省心,不管调用者传什么,你内部用的都是不可变的,不会受外部修改影响,但没法约束调用者的传入行为。


内容的提问来源于stack exchange,提问作者Arun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 00:15:27