java.lang.UnsupportedOperationException分析及解决

        今天在写业务的时候,需要对从数据库返回的List集合根据对象属性进行排序,那么常规的做法就是使用Collections的sort方法,实现Compartor接口重写compare方法,或者直接使用该list的sort方法,但是无论使用那种方法都遇到了这样的报错原因: 

java.lang.UnsupportedOperationException: null
	at java.util.Collections$UnmodifiableList.sort(Collections.java:1333) ~[na:1.8.0_331]
	at java.util.Collections.sort(Collections.java:177) ~[na:1.8.0_331]

         无法支持的操作,再看报错第二行UnmodifiableList,这是一个不可变的集合,它继承 UnmodifiableCollection类,UnmodifiableCollection 中涉及到元素改动(新增、删除、清空…)的方法都直接抛出 UnsupportedOperationException 异常,并不改动元素;Iterator 中涉及到元素修改的方法也一样不进行元素的改动。

        那么是不是把这个集合变成可变的集合问题是不就解决了呢?

list = new ArrayList(list);

         在排序前给这个list再次封装,问题得以解决。

static class UnmodifiableList extends UnmodifiableCollection
                                  implements List {
        private static final long serialVersionUID = -283967356065247728L;

        final List list;

        UnmodifiableList(List list) {
            super(list);
            this.list = list;
        }

        public boolean equals(Object o) {return o == this || list.equals(o);}
        public int hashCode()           {return list.hashCode();}

        public E get(int index) {return list.get(index);}
        public E set(int index, E element) {
            throw new UnsupportedOperationException();
        }
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
        public E remove(int index) {
            throw new UnsupportedOperationException();
        }
        public int indexOf(Object o)            {return list.indexOf(o);}
        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
        public boolean addAll(int index, Collection c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void replaceAll(UnaryOperator operator) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void sort(Comparator c) {
            throw new UnsupportedOperationException();
        }

        public ListIterator listIterator()   {return listIterator(0);}

        public ListIterator listIterator(final int index) {
            return new ListIterator() {
                private final ListIterator i
                    = list.listIterator(index);

                public boolean hasNext()     {return i.hasNext();}
                public E next()              {return i.next();}
                public boolean hasPrevious() {return i.hasPrevious();}
                public E previous()          {return i.previous();}
                public int nextIndex()       {return i.nextIndex();}
                public int previousIndex()   {return i.previousIndex();}

                public void remove() {
                    throw new UnsupportedOperationException();
                }
                public void set(E e) {
                    throw new UnsupportedOperationException();
                }
                public void add(E e) {
                    throw new UnsupportedOperationException();
                }

                @Override
                public void forEachRemaining(Consumer action) {
                    i.forEachRemaining(action);
                }
            };
        }

        public List subList(int fromIndex, int toIndex) {
            return new UnmodifiableList(list.subList(fromIndex, toIndex));
        }

        /**
         * UnmodifiableRandomAccessList instances are serialized as
         * UnmodifiableList instances to allow them to be deserialized
         * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList).
         * This method inverts the transformation.  As a beneficial
         * side-effect, it also grafts the RandomAccess marker onto
         * UnmodifiableList instances that were serialized in pre-1.4 JREs.
         *
         * Note: Unfortunately, UnmodifiableRandomAccessList instances
         * serialized in 1.4.1 and deserialized in 1.4 will become
         * UnmodifiableList instances, as this method was missing in 1.4.
         */
        private Object readResolve() {
            return (list instanceof RandomAccess
                    ? new UnmodifiableRandomAccessList(list)
                    : this);
        }
    }

        这里从UnmodifiableList的源码来分析:除了equals、hashCode、get、indexOf、lastIndexOf等方法外,其他方法都会抛出UnsupportedOperationException()异常,而这些方法的共同点都是返回该list的属性,说明UnmodifiableList是一个只读的集合,因此对这个List不能进行添加或删除元素等操作。

        如果需要将list转化为不可变的集合,Collections也提供了这样的方法,最终转化为UnmodifiableList。

  public static  List unmodifiableList(List list) {
        return (list instanceof RandomAccess ?
                new UnmodifiableRandomAccessList(list) :
                new UnmodifiableList(list));
    }

        同样的 Collections 集合类中的 unmodifiableMap、unmodifiableSet也是只读内部类。它们可以在多线程环境下使用,或者在需要保护列表免受修改的场景下使用。

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/0e22ff41d7.html