【问题标题】:Does Java have an equivalent to Python's list.sorted() method for ArrayLists?Java 是否有与 Python 的 ArrayLists 的 list.sorted() 方法等效的方法?
【发布时间】:2021-09-17 06:11:14
【问题描述】:

我知道我可以在 Java 中对 ArrayList 调用 Collections.sort(),但我目前正在尝试重载构造函数,而在第二个构造函数中我想调用第一个构造函数。但是,我想将排序列表作为参数之一传递,但 Java 不允许我在对列表排序后调用 this() - 它要求 this() 是第一行。我可以将Collections.sort(myList) 放在构造函数中,但我不知道这个方法是否返回排序列表,但理想情况下我想返回排序列表而不改变原始列表。

这是我的代码(适用于您在学校或大学中找到的一段时间),包括错误:

public class Period {

    private String name;
    private LocalDateTime start;
    // duration in seconds
    private int duration;
    private Lecturer lecturer;
    private ArrayList<Demonstrator> dems;
    private ArrayList<Skill> skills;
    
    public Period(String name, LocalDateTime start, int duration, Lecturer lecturer) {
        this.name = name;
        this.start = start;
        this.duration = duration;
        this.lecturer = lecturer;
        this.dems = new ArrayList<>();
        this.skills = new ArrayList<>();
    }
    
    public Period(String name, ArrayList<AvailBlock> blocks, Lecturer lecturer) {
        // this line is illegal, but shows you what I'm trying to do.
        Collections.sort(blocks);
        this(name, blocks.get(0).getStart(), ( blocks.size() * AvailBlock.LENGTH ), lecturer);
    }
    ...
}

AvailBlock 类具有作为LocalDateTime 对象的开始时间和固定的持续时间(当前为 15 分钟)。我正在尝试创建一个持续时间以秒为单位的周期,或者只是传入AvailBlock 对象列表并让它确定周期何时开始以及应该多长时间。

这是AvailBlock 类的开头:

public class AvailBlock implements Comparable {
    
    // the start time of the slot
    private LocalDateTime start;
    // Length of slots in seconds
    public static final int LENGTH = 900;
    
    public AvailBlock(LocalDateTime start) {
        this.start = start;
    }
    ...
}

【问题讨论】:

  • 如果您发现自己在构造函数中做着重要的工作,您可以考虑将其改为静态工厂方法。通常,当我调用构造函数时,我希望它只是分配一些字段,进行一些基本的错误检查,以及将类的工作实例返回给我所需的绝对最少的工作量。
  • 谢谢。我已经创建了第三个构造函数,但它看起来有点乱 - 我会研究静态工厂方法,因为我不熟悉它。
  • @SilvioMayolo “创建此对象列表的托管、排序副本”对于某些管理器对象来说是一项非常普通的任务。

标签: java sorting arraylist overloading


【解决方案1】:

制作静态工厂方法

作为commented by Mayolo,我会在静态方法而不是构造函数中完成这项工作。最好让构造函数完全简单。

此外,构造函数的第一行必须是对超级构造函数的隐式或显式调用。因此,在调用this( … ) 之前,我们不能拥有诸如您对Collections.sort 的调用之类的代码。这一定是您在说“//这条线是非法的,但向您展示了我正在尝试做的事情”时提到的问题。第一行作为超级构造函数调用的 Java 语言要求是使用静态工厂方法解决问题的另一个原因。

我会根据java.time naming conventions 将方法命名为from

public static Period from ( … )
{
    …
    return new Period( … ) ;
}

用法:

Period p = Period.from( … ) ;

复制输入列表

你说:

我可以将 Collections.sort(myList) 放在构造函数中,但我不知道此方法是否返回排序列表,但理想情况下我希望返回排序列表而不改变原始列表。

在排序前复制列表。然后你避免改变原来的。

要进行浅拷贝,您可以将任何Collection 传递给ArrayList 的构造函数

另外,请注意,由于我们先复制然后排序,所以您的工厂方法可以采用任何类型的List,而不仅仅是ArrayList。实际上,任何类型的Collection 都可以接受。

public static Period from ( String name, Collection< AvailBlock > blocks, Lecturer lecturer )
{
    ArrayList< AvailBlock > blocksSorted = new ArrayList<>( blocks ) ;
    Collections.sort( blocksSorted );
    return new Period( name, blocksSorted.get(0).getStart(), ( blocks.size() * AvailBlock.LENGTH ), lecturer ) ;
}

List.copyOf

如果您想要一个不可修改的副本,请将您的列表传递给List.copyOf


record

顺便说一下,records 功能添加到Java 16 可能会很方便。

记录是编写类的一种简短方式,其主要目的是透明且不可变地传递数据。您只需要声明每个成员字段的类型和名称。编译器隐式创建构造函数、getter、equals & hashCodetoString

记录可以携带我们在解决方案中需要的静态工厂方法。

【讨论】:

  • 非常感谢您的深入回复。所以,如果我有类似 x = new ArrayList&lt;SomeType&gt;(someCollection); 的东西,那会像 python 的 x = someCollection.copy() 吗?在这种情况下,浅拷贝正是我想要的。那个录音的东西听起来很有用,我会研究一下。
  • @Donagh 我不懂 Python。但是,是的,将Collection(例如List)传递给ArrayList 的构造函数会产生一个新的List/Collection,其中包含对原始对象中所有相同对象的引用。例如,如果您从一个包含十个对象的十个引用的列表开始,在传递给构造函数后,您将有两个列表,每个列表有十个引用,总共有二十个引用,但相同的原始十个对象,每个十个对象被引用两次,每个列表一次(原始列表和新列表)。
  • 谢谢。是的,这就是 Python 的 .copy() 方法所做的——我不记得在 Python 中进行了多深的复制,但这不是我想要的。感谢您的澄清(我实际上一直想知道new ArrayList&lt;&gt;() 是否可以提出论点,所以现在我知道了!)。
【解决方案2】:

我会回应其他 cmets 关于在构造函数中没有做太多事情的说法。但是,如果您确实想要在不改变原始列表的情况下进行内联排序,那么流似乎是最自然的方式。您可以很容易地进行排序,而无需改变原始列表:

blocks.stream().sorted().collect(Collectors.toList())

(...这将返回一个排序列表,您可以使用内联或分配给变量。)

【讨论】:

  • 很高兴知道,但我觉得前面的建议可能更具可读性。
猜你喜欢
  • 1970-01-01
  • 2012-02-17
  • 2013-06-03
  • 1970-01-01
  • 2014-04-06
  • 2019-03-07
  • 1970-01-01
  • 2018-12-03
  • 2013-09-23
相关资源
最近更新 更多