为什么Java中不存在名为`SortedList`的集合?| Java Debug 笔记

为什么Java中不存在名为`SortedList`的集合?| Java Debug 笔记

技术杂谈小彩虹2021-08-16 5:40:23220A+A-

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看<活动链接>

为什么Java中不存在名为SortedList的集合?

在Java中有SortedSortedMap接口。两者都属于Java集合框架,并提供了对集合元素排序的方法。

然后,据我所知,Java中并没有SortedList这个集合,你需要使用java.util.Collections.sort()对集合进行排序。

为何Java要如此设计呢?

回答一

因为List的概念与自动排序集合的概念不兼容。List的意义在于:在调用List.add(7, elem)之后,对List.get(7)的调用将返回elem。使用自动排序的List,元素可能会出现在任意位置。

回答二

列表迭代器首先保证你能按照列表的内部顺序获取元素。更具体的说,是按照插入元素或者操作集合的顺序。排序可以看作是对数据结构的操作,有几种方法可以对列表进行排序。

我将按照我个人认为有用的顺序来排列这些方法:

考虑使用SetBag集合来替代

注意:我把这个选项放在最上面,因为这是你通常想要做的。

一个SortedSet会在插入元素的时候自动对集合进行排序,这意味这它在添加元素时进行排序,也意味着你不需要手动排序。

此外,如果你确定不需要担心重复元素,那么可以使用TreeSet来代替。它实现SortedSetNavigableSet接口,它们会满足你对集合的需求。

TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding

for (String s : set) {
    System.out.println(s);
}
// Prints out "cat" and "lol"

如果你不想要通过默认的方式进行排序,也可以给构造函数传递一个Comparator<T>参数来自定义排序。

或者,你可以使用Multisets(也称为Bags),这是一个允许重复元素的Set,并且有第三方实现。最值得注意的是,在Guava库中有一个TreeMultiset,它的工作原理与TreeSet非常相似。

通过Collections.sort()方法对集合进行排序

如上所述,列表排序是对数据结构的操作。如果你希望获得一个元素顺序和你操作顺序保持一致的集合,而非自动排序后的集合。那么在这么多种排序中,手动排序是最终的选择。

你可以使用java.util.Collections.sort()对集合进行排序,下面是一个代码示例:

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

Collections.sort(strings);
for (String s : strings) {
    System.out.println(s);
}
// Prints out "cat" and "lol"
  • 使用比较器

在排序方法中使用Compartor是一个很好的选择。Java还为Comparotr提供了一些实现,比如Collator。它对于字符位置敏感的字符串排序非常有用,下面是一个例子:

Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing

Collections.sort(strings, usCollator);
  • 在并行环境下的排序

需要注意的是,在并发环境中使用sort方法并不友好,因为集合实例将会被操作,因此你需要考虑使用不可变集合。下面是Guava在Ordering类中提供的一个简单单行程序:

List<string> sorted = Ordering.natural().sortedCopy(strings);

将你的集合用java.util.PriorityQueue包装

尽管Java中没有SortedList,但是有一个排序队列,它可以像你期望的SortedList那样为你工作,它就是java.util.PriorityQueue类。

在集合的排序过程中,你很可能不希望操作内部数据结构,这就是PriorityQueue不实现List接口的原因(因为这样你可以直接访问集合中的元素)

关于PriorityQueue的迭代器的说明。

PriorityQueue实现了Iterable<E>和Collection接口因此可以像往常一样迭代。但是,迭代器不能保证安排序顺序返回元素。相反,你需要轮询队列,直到队列为空。

注意:你可以把任何Collection传入PriorityQueue的构造函数中,以将这些集合转换为PriorityQueue

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
    System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"

自己造一个名为SortedList的类。

注意:你不是必须创建这个类

你可以编写一个自己的List类,每当你向其中插入新元素的时候都会自动排序。这可能会导致相当大的计算量,这取决于你是如何实现这个类的。实现这个类其实毫无意义,除非你想要用它来练手。因为主要有两个原因:

  1. 它打破了List<E>接口的约定,因为add()方法应该确保元素驻留在用户指定的索引中。
  2. 为什么要重新造个轮子呢?你应该使用TreeSetMultises来代替上面第一点指出的方法。但是,如果你想将其作为一个练习来做,这里有一个代码示例,它继承了抽象类AbstractList<E>
public class SortedList<E> extends AbstractList<E> {

    private ArrayList<E> internalList = new ArrayList<E>();

    // Note that add(E e) in AbstractList is calling this one
    @Override 
    public void add(int position, E e) {
        internalList.add(e);
        Collections.sort(internalList, null);
    }

    @Override
    public E get(int i) {
        return internalList.get(i);
    }

    @Override
    public int size() {
        return internalList.size();
    }

}

文章翻译自Stack Overflow:stackoverflow.com/questions/8…

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们