有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

集合重复数据消除Java 8流

这里是Java8。我有一个方法checkDupeKeys,它将三个不同的SortedMap实例作为其参数,并且需要验证没有两个SortedMap实例具有相同的键。我迄今为止最好的尝试是:

private void checkDupeKeys(SortedMap<String, Fizz> fizzes, SortedMap<String, Buzz> buzzes,
        SortedMap<String, Foobar> foobars) {}
    List<String> keyNames = new ArrayList<>();

    keyNames.addAll(fizzes.keySet().stream().collect(Collectors.toList()));
    keyNames.addAll(buzzes.keySet().stream().collect(Collectors.toList()));
    keyNames.addAll(foobars.keySet().stream().collect(Collectors.toList()));

    if(keyNames.size() > keyNames.stream().collect(Collectors.toSet()).size()) {
        throw new IllegalArgumentException("Duplicate key names are not allowed.");
    }
}

我相信这是可行的,但是可能有更好的方法(效率等)

我主要担心的是,这种方法不允许我识别哪些键名是重复的。理想情况下,我希望异常消息是:

Duplicate key names are not allowed. You have the following duplicate key names: (1) fizzes["derp"] and buzzes["derp"]. (2) fizzes["flim"] and foobars["flim"]. (3) buzzes["flam"] and foobars["flam"].

如何修改我的(非静态)checkDupeKeys方法以抛出满足此条件的异常?也就是说,我如何访问流中哪些密钥是彼此重复的。我确信我可以使用较旧的Java collections API以艰难的方式实现这一点,但是在这个解决方案中,效率和利用Java 8 API对我来说很重要


共 (2) 个答案

  1. # 1 楼答案

    您要做的第一件事是将所有密钥收集到一个流中:

     Stream<String> keys = Stream.of(
           fizzes.keySet().stream(), 
           buzzes.keySet().stream(), 
           foobars.keySet().stream())
        .flatMap(s -> s);
    

    现在您可以collect将它们放入计数图中:

     Map<String, Long> counts = keys.collect(
         Collectors.groupingBy(Function.identity(),
         Collectors.counting()));
    

    您还可以使用计数过滤条目>;1:

     Set<String> duplicates = counts.entrySet().stream()
                .filter( e -> e.getValue() > 0)
                .map(Entry::getKey)
                .collect(Collectors.toSet());
    

    如果此集合不为空,则引发异常

  2. # 2 楼答案

    如果不太使用Java8的函数式习惯用法,我只需使用Set#retainAll进行每次比较(总共3次)

    见以下代码草案:

    private void checkDupeKeys(SortedMap<String, Fizz> fizzes, 
        SortedMap<String, Buzz> buzzes, 
        SortedMap<String, Foobar> foobars) {
    
        // copies the key set
        Set<String> fizBuzSet = new HashSet<>(fizzes.keySet());
    
        // this removes all elements of the set that aren't present in the given key set
        fizBuzSet.retainAll(buzzes.keySet());
    
        // aggregating dupes if needed
        Map<String, Collection<String>> dupes = new HashMap<>();
        // flag to throw exception if needed
        boolean areThereDupes = false;
    
        if (!fizBuzSet.isEmpty()) {
            areThereDupes = true;
            // TODO log fizBuzSet as set of duplicates between fizzes and buzzes
            // or...
            dupes.put("Fizzes vs Buzzes", fizBuzSet);
        }
        // TODO repeat with fizzes vs foobars, then again with buzzes vs foobars
    
        // you can either log the dupes separately, or use a Map<String,Collection<String>> where the  
        // keys represent a compound of the two SortedMaps being compared and the values represent the actual duplicates  
        // e.g...
        if (areThereDupes) {
            // TODO throw exception with dupes map representation in message
        }
    
    }