为什么LinkedList.get抛出NPE

问题描述 投票:-1回答:3

我有一个奇怪的案例,只发生在生产环境中。

基本上,我们保留每个用户最近的选项的历史记录,然后像这样检索它们:

LinkedList l_recent = ApplicationEnvironment.getUserRecentOptions(username);

for (int i = 0; i < l_recent.size(); i++) {
   l_recent.get(i); // When i == 2 throws a NPE
}

但是堆栈跟踪为空,并且get方法的javadoc仅描述了一个可能的异常:IndexOutOfBoundsException如果index < 0 || index >= size

幸运的是,这仅发生在很少的用户上,我们通过清除最近选项的历史记录来修复它。

但是我仍然很想知道为什么会抛出NPE。

我唯一的猜测是,由于此列表是针对每个用户的,因此同一用户登录的次数可能不止一次,然后我们可能同时调用LinkedList的add或remove方法

编辑1

这里是完整的代码:

import java.util.*;

public class App {
    static class Option {
        private String name;

        Option(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    private static final HashMap<String, LinkedList<Option>> userOptions = new HashMap<>();

    public static LinkedList<Option> getUserRecentOptions(String user) {
        LinkedList<Option> options;

        if (userOptions.containsKey(user)) {
            options = userOptions.get(user);
        } else {
            options = new LinkedList<>();
            userOptions.put(user, options);
        }

        return options;
    }

    public static void addRecentOptionToUser(String user, Option option){
        LinkedList<Option> options = getUserRecentOptions(user);

        for (int i = 0; i < options.size(); i++) {
            Option opt = options.get(i);

            if (opt.getName().equalsIgnoreCase(option.getName())) {
                options.remove(i);
                break;
            }
        }

        options.addFirst(option);

        // Max 4
        if (options.size() > 5) {
            options.removeLast();
        }
    }

    public static void main() {
        LinkedList<Option> recentOptions = getUserRecentOptions("demo");

        for (int i = 0; i < recentOptions.size(); i++) {
            recentOptions.get(i); // Throws NPE when i == 2 (sometimes...)
        }
    }
}
java
3个回答
0
投票

所以不是 get(i)为空。如果执行for (Object lri : l_recent) {,则ConcurrentModificationException可能指向并发问题。但是,LinkedList在用户的最近选项中保持共享状态,并且可能经常更新,因此LinkedList级别太低,无法共享。

制作提供高级访问权限的API:getLatest,getAndRemember,getListCopyOfAll。

存在NPE的原因可能是序列化/反序列化或get的某些内部,或分配了新的List。没有堆栈跟踪似乎指向上下文切换之类的东西。但是,这一切都不基于我这一方面的深刻知识。


0
投票

在for循环中尝试l_recent.size()-1方法返回的大小和列表从0点开始


0
投票

[好吧,这的确是一个多线程问题,如果我从不同的线程多次调用addRecentOptionToUser,则会重现该问题,因为节点为空,将引发NPE。

解决方案显然是使此代码具有线程安全性。

谢谢

© www.soinside.com 2019 - 2024. All rights reserved.