Java 8 : Order a Collection by stream representation date in ascending way using collections streams

254 Views Asked by At

I'm working with DockerClient and I have a collection from images, I need to delete all of them, but not the latest one, so I wanted to sort the collection in ascending way, I have a created field which is a string with the number representation of the date as 1632912516.

I tried the next:

    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());
  }

But I saw, that in the getImages method the collection is not sorted, so I think I need to convert the created field to something different of a String to achieve this.

Any ideas?

3

There are 3 best solutions below

2
On BEST ANSWER

Collections.max()

You don’t need to sort all of your images to find the newest. Collections.max() can do that. Simplified code to illustrate my point:

    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
    }

I understand that Image.created() returns a String holding a Unix timestamp (number of seconds since the Unix epoch in 1970).

1
On

sorted() takes a Comparator, whose single abstract method is compare() as opposed to Comparable's compareTo().

If whatever class is returned by listImages implements Comparable then you could use sorted() without arguments, as compareTo() will be called. However, the Override of compareTo() will need to be comparing whatever field you are considering to the "last one" (is this by date? by name?).

I would also recommend that, instead of creating a String and using that as a number representation of date, you use LocalDateTime (or something similar) if you want to sort information chronologically. Depending on sort implementations Strings as numbers will not sort the same as true numbers (1, 10, 100, 2, 20, 200). From an abstraction perspective, treat dates like dates.

3
On

You could just sort the thing by created-date descending, skip the first (latest) and do the removal for each remaining image:

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();
}