Java List retainAll 记录坑

描述

我们知道使用List的retainAll方法可以获取两个集合的交集,但是在某些情况下方法的返回值并非我们想象那样。

现象

先看两个例子:

   public static void main(String[] args) {
        List<String> a = new ArrayList<>();
        a.add("READ");
        a.add("DELETE");
        a.add("TTT");
        List<String> b = new ArrayList<>();
        b.add("READ");
        b.add("WRITE");
        System.out.println(b.retainAll(a));
        System.out.println(b);
    }

代码运行结果如下:

这个运行结果是我们想要的结果:方法返回true,b集合中剩下交集的元素。

再看个情况

    public static void main(String[] args) {
        List<String> a = new ArrayList<>();
        a.add("READ");
        a.add("DELETE");
        a.add("TTT");
        List<String> b = new ArrayList<>();
        b.add("READ");
        System.out.println(b.retainAll(a));
        System.out.println(b);
    }

运行结果如下:

 

两个集合有交集"READ",但是运行结果返回的是false 

发现这个结果并不是我们想要的true。

我们来查询下源码:注释中写到只有当这个list发生change的时候,才会return true。

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * @param c collection containing elements to be retained in this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean retainAll(Collection<?> c) {
        return batchRemove(c, true, 0, size);
    }

    boolean batchRemove(Collection<?> c, boolean complement,
                        final int from, final int end) {
        Objects.requireNonNull(c);
        final Object[] es = elementData;
        int r;
        // Optimize for initial run of survivors
        for (r = from;; r++) {
            if (r == end)
                return false;
            if (c.contains(es[r]) != complement)
                break;
        }
        int w = r++;
        try {
            for (Object e; r < end; r++)
                if (c.contains(e = es[r]) == complement)
                    es[w++] = e;
        } catch (Throwable ex) {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            System.arraycopy(es, r, es, w, end - r);
            w += end - r;
            throw ex;
        } finally {
            modCount += end - w;
            shiftTailOverGap(es, w, end);
        }
        return true;
    }

下面我们来debug测试下     

       当我们debug到batchRemove的第一个for循环的时候,发现在第二次循环的时候就直接return了false。

       而只有当c中有不包含es的元素的时候,代码才会继续往下走,只要不抛异常就会返回true,从而我们知道方法的返回值对我们取两个集合的交集并没有太大作用。

结论

        方法的返回值仅供参考该list是否发生过元素的remove,而不应该作为两个集合是否有交集的依据。可以通过判断b  list中元素个数是否大于1来判断是否有交集。

### Java 实现电影推荐系统 #### 系统架构与技术选型 构建一个高效的电影推荐系统涉及到多个方面,包括但不限于后端服务搭建、前端交互设计以及核心的推荐算法实现。对于Java开发者而言,可以考虑使用Spring Boot作为后端框架来简化Web应用程序的创建过程[^5]。 #### 推荐算法的选择 针对电影推荐场景,常见的推荐策略有基于内容(Content-Based Filtering)、协同过滤(Collaborative Filtering),甚至更高级别的深度学习模型。其中,协同过滤因其简单有效而被广泛应用于实际项目中。具体来说,可以通过分析用户的历史行为记录(如评分),找出相似兴趣爱好的其他用户群体,进而预测目标用户的潜在偏好并作出相应推荐[^2]。 #### 数据获取与预处理 为了训练有效的推荐引擎,需要收集大量的电影元数据及其对应的观众反馈信息。一种可行的方法是从公开API或第三方平台抓取所需资源,并将其持久化保存至本地数据库以便后续调用。例如,在某些案例里会利用Python编写网络爬虫程序定期更新最新上映作品列表及评价情况[^4]。 #### 核心模块编码实例 下面给出一段简单的代码片段用于模拟基于内存版User-CF(User-based Collaborative Filtering)计算流程: ```java import java.util.*; public class MovieRecommender { private Map<Integer, List<Rating>> userRatings; // 用户ID -> 评分列表映射表 public void addUserRating(int userId, int movieId, double rating){ this.userRatings.computeIfAbsent(userId, k->new ArrayList<>()).add(new Rating(movieId,rating)); } /** * 计算两个用户之间的皮尔逊相关系数 */ private double pearsonCorrelation(List<Rating> ratingsA, List<Rating> ratingsB){ Set<Integer> commonMovies = new HashSet<>(); for (Rating r : ratingsA) commonMovies.add(r.getMovieId()); commonMovies.retainAll(ratingsB.stream().map(Rating::getMovieId).collect(Collectors.toSet())); if(commonMovies.isEmpty()) return 0; double sumXY=0,sumX=0,sumY=0,squareSumX=0,squareSumY=0; for(Integer mid:commonMovies){ double scoreA = ratingsA.stream().filter(x->x.getMovieId()==mid).findFirst().orElseThrow().getScore(); double scoreB = ratingsB.stream().filter(x->x.getMovieId()==mid).findFirst().orElseThrow().getScore(); sumXY +=scoreA*scoreB; sumX+=scoreA; sumY+=scoreB; squareSumX+=Math.pow(scoreA,2); squareSumY+=Math.pow(scoreB,2); } int n = commonMovies.size(); double numerator=sumXY-(sumX*sumY)/n; double denominator=Math.sqrt((squareSumX-Math.pow(sumX,2)/n)*(squareSumY-Math.pow(sumY,2)/n)); return Math.abs(numerator/denominator); } static class Rating{ final int movieId; final double score; public Rating(int id,double s){this.movieId=id;this.score=s;} public int getMovieId(){return movieId;} public double getScore(){return score;} } } ``` 此段代码展示了如何定义`MovieRecommender`类以支持新增用户打分操作(`addUserRating`),并通过Pearson Correlation Coefficient衡量任意两位参与者之间观影品味的一致程度。这一步骤构成了后续生成个性化建议的基础[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值