如何从“不可修改的”地图中删除空列表或空列表

时间:2019-08-04 10:22:35

标签: java java-8

我有一个不可修改的地图(Map<String, Object>)。它包含一个键值对,其中值应为List,但对于特定键,该值为空List。

如何从地图中删除该空列表并返回?

我已经使用谓词完成了它,它检查值是否是collection的实例,然后检查Collections.isNotEmpty(..)。

我想知道还有什么比这更好的方法吗? (在Java 8中)

public class StudentTest {

    Predicate<Object> isCollectionNotEmpty = input -> {
        if (input instanceof Collection) {
            return CommonCollectionUtils.isNotEmpty((Collection<?>)input);
        }
        return true;
    };
    Predicate<Object> isObjectNotNull = input -> Objects.nonNull(input);

    public static void main(String[] args) {

        StudentTest s = new StudentTest();
        final Map<String, Object> map1 = new HashMap<>();
        map1.put("student_batch_size", 200);
        map1.put("student_avg_height", 172);
        map1.put("Student_names", Collections.emptyList());

        final Map<String, Object> finalMap = s.getFinalMap(Collections.unmodifiableMap(map1));

        System.out.println(finalMap);
    }

    private Map<String, Object> getFinalMap(final Map<String, Object> inputMap) {
        final Map<String, Object> resultMap = new HashMap<>();
        //inputMap.values().remove(Collections.emptyList());
        resultMap.putAll(inputMap.entrySet().stream()
            .filter(entry -> isObjectNotNull.and(isCollectionNotEmpty).test(entry.getValue()))
        .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())));
        return resultMap;
    }

}

预期输出:

{student_avg_height=172, student_batch_size=200}

3 个答案:

答案 0 :(得分:3)

Collection#removeIf可能是一个不错的选择。

private Map<String, Object> getFinalMap(final Map<String, Object> inputMap) {
    final Map<String, Object> resultMap = new HashMap<>(inputMap);
    resultMap.entrySet().removeIf(e -> e.getValue() instanceof Collection && ((Collection) e.getValue()).isEmpty());

    return resultMap;
}

如果基于流的方法对您更有吸引力

private Map<String, Object> getFinalMap(final Map<String, Object> inputMap) {
    return inputMap.entrySet()
        .stream()
        .filter(e -> !(e.getValue() instanceof Collection && ((Collection) e.getValue()).isEmpty()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

更新

如果要过滤空对象而不管它们的类型如何,请对上述方法进行一些细微改动

1)removeIf

resultMap.entrySet()
    .removeIf(e -> Objects.isNull(e.getValue()) || 
                   (e.getValue() instanceof Collection && ((Collection) e.getValue()).isEmpty());

2)基于流

.filter(e -> Objects.nonNull(e.getValue()))
.filter(e -> !(e.getValue() instanceof Collection && ((Collection) e.getValue()).isEmpty()))

答案 1 :(得分:2)

我认为您在Object中使用Map作为值的方法值得怀疑。您没有完全控制类型安全。我会考虑用反映单个学生批处理属性的对象替换学生Map

class StudentBatch {
   int size;
   int avgHeight;
   Collection<String> names;

   boolean hasValidNames() {
       return names != null && !names.isEmpty();
   }
}

如您所见,我将hasValidNames谓词放到该对象上,使其可重用,并简化了您要优化的条件。

  List<StudentBatch> batchList = new ArrayList<>();
  batchList.stream().filter(StudentBatch::hasValidNames).collect(Collectors.toList());

答案 2 :(得分:1)

instanceof也会检查是否为null,因此即使您无法像流一样修改地图,也无需显式地创建它,也无需创建新的HashMap不能直接修改它,而是创建一个新的Map:

final Map<String, Object> finalMap =
     map
    .entry()
    .stream()
    .filter(e-> !isEmptyCollection(e))
    .collect(toMap(Entry::getKey, Entry::getValue);


public void boolean isEmptyCollection(Entry<String, Object> entry){     
    return entry.getValue() instanceof Collection && ((Collection<?>) entry.getValue()).isEmpty();
}