【问题标题】:Java 8 : Order a Collection by stream representation date in ascending way using collections streams [duplicate]Java 8:使用集合流按流表示日期以升序方式排序集合[重复]
【发布时间】:2021-11-21 14:19:06
【问题描述】:

我正在使用 DockerClient,我有一个图像集合,我需要删除所有图像,但不是最新的,所以我想按升序对集合进行排序,我有一个创建的字段,它是日期的数字表示为 1632912516 的字符串。

我尝试了下一个:

    public void checkingTest() throws DockerException, InterruptedException {
      try {
      List<com.spotify.docker.client.messages.Image> sortedImages = getImages();

      sortedImages.stream()
          .filter(img -> !img.id().equals(sortedImages.get(sortedImages.size() - 1).id()))
          .forEach(img -> {
            try {
              dockerClient.removeImage(img.id());
            }
            catch (DockerException e) {
              e.printStackTrace();
            }
            catch (InterruptedException e) {
              e.printStackTrace();
            }
          });
    }
    catch (DockerCertificateException e) {
      e.printStackTrace();
    }
  }

  private List<com.spotify.docker.client.messages.Image> getImages()
      throws DockerCertificateException, DockerException, InterruptedException
  {
    final DockerClient dockerClient =
        DefaultDockerClient.fromEnv().connectTimeoutMillis(TimeUnit.SECONDS.toMillis(3)).build();

    return dockerClient.listImages()
        .stream()
        .filter(image -> image.labels() != null && image.labels().containsKey("image"))
        .sorted((o1, o2) -> o2.created().compareTo(o1.created()))
        .collect(
            Collectors.toList());
  }

但我看到,在getImages 方法中,集合没有排序,所以我认为我需要将创建的字段转换为不同的字符串来实现这一点。

有什么想法吗?

【问题讨论】:

  • 我会在 image.labels() != null 周围加上一对括号。
  • 这是一个xy problem,因为您根本不需要排序,如this answer 所示。比较包含数字的字符串可以像Integer.compare(Integer.parseInt(o2.created(), Integer.parseInt(o1.created())) 一样完成,但这只有在字符串具有不同的小数位数时才会有所不同。

标签: java collections java-stream spotify-docker-client


【解决方案1】:

sorted() 采用Comparator,其单一抽象方法是compare(),而不是ComparablecompareTo()

如果listImages 返回的任何类都实现了Comparable,那么您可以使用不带参数的sorted(),因为将调用compareTo()。但是,compareTo() 的覆盖将需要将您正在考虑的任何字段与“最后一个”进行比较(这是按日期吗?按名称?)。

我还建议不要创建String 并将其用作日期的数字表示,而是使用LocalDateTime(或类似的东西),如果您想按时间顺序对信息进行排序。取决于排序实现Strings,因为数字不会与真实数字(1、10、100、2、20、200)排序相同。从抽象的角度来看,将日期视为日期。

【讨论】:

  • 我正在使用一个库,在这个库的响应中创建的字段是字符串我无法将其类型更改为 LocalDateTime
【解决方案2】:

您可以按创建日期降序对事物进行排序,跳过第一个(最新)并删除剩余的每个图像:

try{
final DockerClient dockerClient = DefaultDockerClient.fromEnv()
.connectTimeoutMillis(TimeUnit.SECONDS.toMillis(3)).build();
    dockerClient.listImages()
            .stream()
            .filter(image -> image.labels() != null && image.labels().containsKey("image"))
            .sorted(Comparator.comparing(Image::created).reversed()).skip(1)
            .forEach(img -> {
            try {
              dockerClient.removeImage(img.id());
            catch(Exception ex){
              ex.printStackTrace();
            }
            );
}catch (Exception e){
   e.printStackTrace();
}

      

【讨论】:

  • 在这种情况下,我们按 created 排序,它是一个字符串,它会起作用吗?
  • 它将适用于 2001 年 9 月 8 日晚上 9:47 之后的日期,这是 unix 纪元毫秒计数器从 999999999 变为 1000000000 的时间——除非你用零填充字符串值,其中情况下它会一直工作到 2286 年。因此,为了安全起见,可能会将其填充到 11 位数字。
  • --或使用比较器@Ole V.V.建议的,颠倒的——Comparator.comparingLong(img -&gt; Long.parseLong(img.created())).reversed()
【解决方案3】:

Collections.max()

您无需对所有图片进行排序即可找到最新的。 Collections.max() 可以做到这一点。简化代码来说明我的观点:

    List<Image> unsortedImages = // …;
    if (! unsortedImages.isEmpty()) {
        Id latestId = Collections.max(unsortedImages,
                        Comparator.comparingLong(img -> Long.parseLong(img.created())))
               .id();
         // Proceed with deleting as in your code
    }

我知道 Image.created() 返回一个 String 持有 Unix 时间戳(自 1970 年 Unix 纪元以来的秒数)。

【讨论】:

  • 创建的字段是一个带有日期表示的字符串数字,我很好奇这是否可行
  • 如果数字总是正好是 10 位数字,它会。但是不要在没有检查的情况下依赖这个。我已经编辑了答案。
猜你喜欢
  • 1970-01-01
  • 2016-07-10
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2015-01-19
  • 2016-01-06
相关资源
最近更新 更多