Java 8使用Stream按created时间戳升序排序Docker镜像并清理旧镜像咨询
问题根因
你当前使用created()返回的字符串做排序,字符串默认按字典序比较,虽然同长度的数字字符串排序结果和数值排序一致,但如果存在不同长度的时间戳(如极旧镜像的9位秒级时间戳、部分Docker版本返回带毫秒的更长时间戳字符串),就会出现排序错误,不符合按时间先后排序的预期。
同时你的代码还存在两处逻辑偏差需要同步修正:
- 排序后的列表如果按创建时间降序排列,最新镜像在列表首位,你当前保留最后一个元素的逻辑刚好取到了最旧的镜像
getImages方法内单独创建了DockerClient实例,和外层删除用的不是同一个实例,存在资源冗余
可行解决方案
步骤1:修正排序逻辑,将时间戳转为Long类型比较
修改getImages方法的sorted排序规则,先把字符串类型的时间戳转为Long再比较,示例代码如下:
private List<com.spotify.docker.client.messages.Image> getImages() throws DockerCertificateException, DockerException, InterruptedException { // 建议把DockerClient实例抽成全局共用,避免重复创建连接,这里先保持你原有写法 final DockerClient dockerClient = DefaultDockerClient.fromEnv().connectTimeoutMillis(TimeUnit.SECONDS.toMillis(3)).build(); return dockerClient.listImages() .stream() .filter(image -> image.labels() != null && image.labels().containsKey("image")) // 转为Long后按时间降序排序,最新的排在列表最前面 .sorted((o1, o2) -> { Long t1 = Long.parseLong(o1.created()); Long t2 = Long.parseLong(o2.created()); // 降序排列,用t2减t1 return t2.compareTo(t1); }) .collect(Collectors.toList()); }
如果要兼容created为空的异常场景,可以加空判断,把空值的镜像排在列表末尾优先删除:
.sorted((o1, o2) -> { if (o1.created() == null) return 1; if (o2.created() == null) return -1; Long t1 = Long.parseLong(o1.created()); Long t2 = Long.parseLong(o2.created()); return t2.compareTo(t1); })
步骤2:修正镜像保留逻辑
排序后最新镜像在列表第一位,修改过滤规则,保留第一个元素即可:
public void checkingTest() throws DockerException, InterruptedException { try { List<com.spotify.docker.client.messages.Image> sortedImages = getImages(); // 列表为空直接返回,避免索引越界 if (sortedImages.isEmpty()) { return; } // 跳过第一个(最新)镜像,删除剩下的所有 sortedImages.stream() .skip(1) .forEach(img -> { try { // 建议共用同一个DockerClient实例,这里可以把dockerClient作为参数传入或者抽成全局 dockerClient.removeImage(img.id()); } catch (DockerException | InterruptedException e) { e.printStackTrace(); } }); } catch (DockerCertificateException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者rasilvap
相关产品推荐
相关产品推荐

