Java集合sort排序报错UnsupportedOperationException处理

文章目录

报错场景

  • 我们使用的是PostgreSQL数据库,存储业务数据,业务代码使用的是Spring JPA
  • 我们做的是智慧交通信控平台,有个功能是查询展示区域的交通态势,需要按照不同维度排序展示
  • 区域态势指标计算,15分钟一次,每次计算存储所有区域指标。我们的实时态势展示,每次展示当前最新结果
  • 业务要求,要按照区域交通流量、拥堵指数、拥堵里程分别倒序展示,写在了一个接口里,先查询后排序
  • 我们使用的默认自增的主键策略,故获取最新一次区域态势结果,可以使用id倒序,按照区域数量获取
  • 查询的业务逻辑比较简单,代码很快就写完了,使用JPA查询语句,构造查询和排序条件。得到查询结果list后,再根据业务需要,按照不同的字段排序
  • 但在部署测试环境后发现,排序代码执行报错,报错 null Not Implemented
  • 具体业务代码如下
java 复制代码
    /**
     * 获取所有区域实时态势
     * @param targetIndex 排序字段
     * @return 
     */
    public List<SituationAnalysisRegion> getCurrentRegionSituationList(String targetIndex) {
        // 获取所有子区
        List<SubRegion> allSubRegions = getAllSubRegion();
        Map<Integer, SubRegion> idSubRegionMap = new HashMap<>();
        allSubRegions.forEach(e -> idSubRegionMap.put(e.getId().intValue(), e));
        // 获取所有子区态势排名倒序
        Specification<SituationAnalysisRegion> specification = (root, query, cb)->{
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.greaterThan(root.get("timeStamp").as(Instant.class), LocalDateTime.now().plusMinutes(-15).plusSeconds(-30).atZone(ZoneId.systemDefault()).toInstant()));
            Predicate[] pre = new Predicate[predicates.size()];
            pre = predicates.toArray(pre);
            return query.where(pre).getRestriction();
        };
        Sort orders = Sort.by("id").descending();
        Pageable pageable = PageRequest.of(0, allSubRegions.size(), orders);
        List<SituationAnalysisRegion> situationAnalysisRegions = analysisRegionRepository.findAll(specification, pageable).getContent();
        // 排序要求
        if (null == targetIndex || StringUtils.isEmpty(targetIndex)) {
            situationAnalysisRegions.sort((o1, o2) -> (int)(o2.getCongestionMileage() - o1.getCongestionMileage()));
        } else if (targetIndex.equals("trafficFlow")) {
            situationAnalysisRegions.sort((o1, o2) -> o2.getTrafficFlow() - o1.getTrafficFlow());
        } else if (targetIndex.equals("congestionIndex")) {
            situationAnalysisRegions.sort((o1, o2) -> (int)(o2.getCongestionIndex() - o1.getCongestionIndex()));
        } else {
            situationAnalysisRegions.sort((o1, o2) -> (int)(o2.getCongestionMileage() - o1.getCongestionMileage()));
        }
        return situationAnalysisRegions;
    }
  • 具体报错日志如下:

    2023-08-29 16:12:56.168 ERROR 12860 --- [ XNIO-1 task-1] o.z.problem.spring.common.AdviceTraits : Not Implemented

    java.lang.UnsupportedOperationException: null
    at java.base/java.util.CollectionsUnmodifiableList.sort(Collections.java:1332) at com.newatc.api.situationanalysis.service.SituationAnalysisRegionExtentService.getCurrentRegionSituationList(SituationAnalysisRegionExtentService.java:88) at com.newatc.api.situationanalysis.service.SituationAnalysisRegionExtentService.getRegionSituationList(SituationAnalysisRegionExtentService.java:104) at com.newatc.api.rest.SituationAnalysisController.getRegionSituationList(SituationAnalysisController.java:112) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:497) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:129)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131) at com.newatc.api.redis.RequestFilter.doFilter(RequestFilter.java:58) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:327) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter.doFilterInternal(OAuth2AuthorizationCodeGrantFilter.java:168)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:125)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:178) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.springframework.security.web.FilterChainProxyVirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandlerFilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
    at io.undertow.server.HttpServerExchange1.run(HttpServerExchange.java:852) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019) at org.jboss.threads.EnhancedQueueExecutorThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
    at org.jboss.threads.EnhancedQueueExecutorThreadBody.run(EnhancedQueueExecutor.java:1449) at org.xnio.XnioWorkerWorkerThreadFactory$1$1.run(XnioWorker.java:1282)
    at java.base/java.lang.Thread.run(Thread.java:834)

    2023-08-29 16:12:56.227 WARN 12860 --- [ XNIO-1 task-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [java.lang.UnsupportedOperationException]

排查解决

  • 日志核心打印:Not Implementedjava.lang.UnsupportedOperationException: nullat java.base/java.util.Collections$UnmodifiableList.sort(Collections.java:1332)

  • 一开始看着报错null,以为是空指针异常,想着是不是没查询到数据,或者排序字段的值有null值

  • 查看了数据库数据,发现没问题,只好本地debug排查

  • 加了断点,进行debug,确认返回结果list有值,且排序字段也都有值,继续执行,还是这个报错

  • 想着要进行更细粒度的debug,于是按着 F5 继续调试,结果发现,也是直接一步走进报错,在这一行(Collections.sort)

  • 一下子没法排查了,这个报错之前也没注意过,于是继续去网上搜索相应报错,还真找到了

  • 还是要回到报错日志,核心是这一句:at java.base/java.util.Collections$UnmodifiableList.sort(Collections.java:1332)

  • 在执行Collections.sort()方法时,发现传入的集合list,是一个不可修改的UnmodifiableList.,不能直接拿来排序

  • 但是可以通过新建一个list,来解决这个问题

java 复制代码
        List<SituationAnalysisRegion> situationAnalysisRegions = analysisRegionRepository.findAll(specification, pageable).getContent();
        // 重新赋值,排除 UnmodifiableList 报错
        List<SituationAnalysisRegion> result = new ArrayList<>(situationAnalysisRegions);
        // 排序要求
        if (null == targetIndex || StringUtils.isEmpty(targetIndex)) {
            result.sort((o1, o2) -> (int)(o2.getCongestionMileage() - o1.getCongestionMileage()));
        } else if (targetIndex.equals("trafficFlow")) {
            result.sort((o1, o2) -> o2.getTrafficFlow() - o1.getTrafficFlow());
        } else if (targetIndex.equals("congestionIndex")) {
            result.sort((o1, o2) -> (int)(o2.getCongestionIndex() - o1.getCongestionIndex()));
        } else {
            result.sort((o1, o2) -> (int)(o2.getCongestionMileage() - o1.getCongestionMileage()));
        }
        return result;
  • 现在问题很明确了,JPA的查询代码,返回的list,是个不可修改的list。在网上查询该问题时,发现其他的一些类似查询,也可能返回一个不可修改的list,如 MongoDB的Java查询语句
  • 以后如果看到Collections$UnmodifiableList.sort报错,就要考虑到这种情况,都可以类似处理

UnmodifiableList类介绍

  • UnmodifiableList类是Collections的内部类

  • Java的Collections框架提供了UnmodifiableList类作为不可变列表的一种实现

  • UnmodifiableList实现了List接口,但是在其基础上增加了一些限制,例如不允许修改列表中的元素、不允许添加新元素以及不允许删除已有元素。因此,可以使用UnmodifiableList来保护某些关键数据,防止其他程序修改它们

  • 使用方式非常简单,通过Collections.unmodifiableList(List list)方法可以将一个可变的列表转换为一个不可变的列表,例如:

    List<String> mutableList = new ArrayList<>();
    mutableList.add("apple");
    mutableList.add("banana");
    mutableList.add("orange");

    List<String> immutableList = Collections.unmodifiableList(mutableList);

  • 这样,immutableList就成为了一个不可变的列表,任何尝试修改、添加或删除其中的元素的操作都会抛出UnsupportedOperationException异常。

相关推荐
_oP_i21 分钟前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx24 分钟前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康1 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上3 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人3 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.3 小时前
Mybatis-Plus
java·开发语言
不良人天码星3 小时前
lombok插件不生效
java·开发语言·intellij-idea