gpt4 book ai didi

java-8 - 与流 API 交换实现后 Junit 测试失败,为什么?

转载 作者:行者123 更新时间:2023-12-04 14:37:50 26 4
gpt4 key购买 nike

我已经实现了以下方法,该方法提供了对 String 的概述。 s 及其在 Map<String, List<String>> 的值中的出现:

public static Map<String, Long> getValueItemOccurrences(Map<String, List<String>> map) {
Map<String, Long> occurrencesOfValueItems = new HashMap<>();

map.forEach((key, value) -> {
value.forEach(item -> {
if (occurrencesOfValueItems.containsKey(item)) {
occurrencesOfValueItems.put(item, occurrencesOfValueItems.get(item) + 1);
} else {
occurrencesOfValueItems.put(item, 1L);
}
});
});

return occurrencesOfValueItems;
}

我已经使用单个 JUnit 测试对其进行了测试,并且测试成功。这是( 现在还包括进口 ):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

class TryoutTest {

static Map<String, List<String>> items = new HashMap<>();
static List<String> largeList = new ArrayList<String>();
static List<String> mediumList = new ArrayList<String>();
static List<String> smallList = new ArrayList<String>();
static List<String> differentLargeList = new ArrayList<String>();
static List<String> differentSmallList = new ArrayList<String>();
static List<String> anotherList = new ArrayList<String>();
static List<String> someList = new ArrayList<String>();
static List<String> justAList = new ArrayList<String>();

@BeforeAll
static void setup() {
largeList.add("Alfred");
largeList.add("Bakari");
largeList.add("Christian");
largeList.add("Dong");
largeList.add("Etienne");
largeList.add("Francesco");
largeList.add("Guido");
largeList.add("Henrik");
largeList.add("Ivan");
largeList.add("Jos");
largeList.add("Kumar");
largeList.add("Leonard");
largeList.add("Marcin");
largeList.add("Nico");
largeList.add("Olof");
items.put("fifteen-01", largeList);

mediumList.add("Petar");
mediumList.add("Quentin");
mediumList.add("Renato");
mediumList.add("Sadio");
mediumList.add("Tomislav");
mediumList.add("Ulrich");
mediumList.add("Volkan");
mediumList.add("Wladimir");
items.put("eight-01", mediumList);

smallList.add("Xavier");
smallList.add("Yves");
smallList.add("Zinedine");
smallList.add("Alfred");
items.put("four-01", smallList);

differentLargeList.add("Bakari");
differentLargeList.add("Christian");
differentLargeList.add("Dong");
differentLargeList.add("Etienne");
differentLargeList.add("Francesco");
differentLargeList.add("Xavier");
differentLargeList.add("Yves");
differentLargeList.add("Wladimir");
differentLargeList.add("Jens");
differentLargeList.add("Hong");
differentLargeList.add("Le");
differentLargeList.add("Leigh");
differentLargeList.add("Manfred");
differentLargeList.add("Anders");
differentLargeList.add("Rafal");
items.put("fifteen-02", differentLargeList);

differentSmallList.add("Dario");
differentSmallList.add("Mohammad");
differentSmallList.add("Abdul");
differentSmallList.add("Alfred");
items.put("four-02", differentSmallList);

anotherList.add("Kenneth");
anotherList.add("Hong");
anotherList.add("Bakari");
anotherList.add("Ulrich");
anotherList.add("Henrik");
anotherList.add("Bernd");
anotherList.add("Samuel");
anotherList.add("Ibrahim");
items.put("eight-02", anotherList);

someList.add("Kumar");
someList.add("Konrad");
someList.add("Bakari");
someList.add("Francesco");
someList.add("Leigh");
someList.add("Yves");
items.put("six-01", someList);

justAList.add("Bakari");
items.put("one-01", justAList);
}

@Test
void valueOccurrencesTest() {
Map<String, Integer> expected = new HashMap<>();
expected.put("Abdul", 1);
expected.put("Alfred", 3);
expected.put("Anders", 1);
expected.put("Bakari", 5);
expected.put("Bernd", 1);
expected.put("Christian", 2);
expected.put("Dario", 1);
expected.put("Dong", 2);
expected.put("Etienne", 2);
expected.put("Francesco", 3);
expected.put("Guido", 1);
expected.put("Henrik", 2);
expected.put("Hong", 2);
expected.put("Ibrahim", 1);
expected.put("Ivan", 1);
expected.put("Jens", 1);
expected.put("Jos", 1);
expected.put("Kenneth", 1);
expected.put("Konrad", 1);
expected.put("Kumar", 2);
expected.put("Le", 1);
expected.put("Leigh", 2);
expected.put("Leonard", 1);
expected.put("Manfred", 1);
expected.put("Marcin", 1);
expected.put("Mohammad", 1);
expected.put("Nico", 1);
expected.put("Olof", 1);
expected.put("Petar", 1);
expected.put("Quentin", 1);
expected.put("Rafal", 1);
expected.put("Renato", 1);
expected.put("Sadio", 1);
expected.put("Samuel", 1);
expected.put("Tomislav", 1);
expected.put("Ulrich", 2);
expected.put("Volkan", 1);
expected.put("Wladimir", 2);
expected.put("Xavier", 2);
expected.put("Yves", 3);
expected.put("Zinedine", 1);
assertThat(FunctionalMain.getValueItemOccurrences(items), is(expected));
}
}

当我将方法的实现更改为
public static Map<String, Long> getValueItemOccurrences(Map<String, List<String>> map) {
return map.values().stream()
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

测试用例失败,说明结果映射不等于预期的映射。看这个 eclipse 截图,它表明,显然,元素的顺序使测试失败:

enter image description here

真的只是这样吗?我想我已经读过 HashMap s 通常不保证任何键的顺序。

我的(相当长的)问题是:我该怎么做才能使流 API 调用产生通过测试的结果,或者我是否必须更改测试用例,也许使用不同的断言?

一些子问题是:
  • 有没有替代/更好的方法来为这个方法使用流 API?
  • 我是否必须返回特定的 Map如果订单很重要,则实现( TreeMap ,也许)?
  • 最佳答案

    TL;博士 你的测试坏了,修复它。

    首先,使用以下方法更容易重新生成:

    List<String> list = ImmutableList.of("Kumar", "Kumar", "Jens");

    public static Map<String, Long> getValueItemOccurrences1(List<String> list) {
    return list
    .stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    }

    public static Map<String, Long> getValueItemOccurrences2(List<String> list) {
    Map<String, Long> occurrencesOfValueItems = new HashMap<>();

    list.forEach(item -> {
    if (occurrencesOfValueItems.containsKey(item)) {
    occurrencesOfValueItems.put(item, occurrencesOfValueItems.get(item) + 1);
    } else {
    occurrencesOfValueItems.put(item, 1L);
    }
    });

    return occurrencesOfValueItems;
    }

    问题是在内部 HashMap::hash之后(也称为重新散列)并获取在决定选择哪个桶时实际重要的最后一位,它们具有相同的值:
        System.out.println(hash("Kumar".hashCode()) & 15);
    System.out.println(hash("Jens".hashCode()) & 15);

    简单来说,一个 HashMap根据 hashCode 决定放置条目的位置(选择存储桶)您的条目。嗯,差不多,曾经 hashCode被计算,内部还有另一个 hash done - 更好地分散条目。那最后 int hashCode 的值用于决定桶。当您创建一个默认容量为 16 的 HashMap 时(例如,通过 new HashMap),只有最后 4 位与条目的去向有关(这就是为什么我在那里做了 & 15 - 查看最后 4 位)。

    哪里 hash是 :
    // xor first 16 and last 16 bits
    static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    现在,事实证明 ["Kumar" and "Jens"]["Xavier", "Kenneth", "Samuel"]应用上述算法后具有相同的最后 4 位数字(第一种情况下为 3,第二种情况下为 1)。

    现在我们知道了这些信息,这实际上可以进一步简化:
    Map<String, Long> map = new HashMap<>();
    map.put("Kumar", 2L);
    map.put("Jens", 1L);

    System.out.println(map); // {Kumar=2, Jens=1}

    map = new HashMap<>();
    map.computeIfAbsent("Kumar", x -> 2L);
    map.computeIfAbsent("Jens", x -> 1L);
    System.out.println(map); // {Jens=1, Kumar=2}

    我用过 map.computeIfAbsent因为这就是 Collectors.groupingBy正在使用引擎盖下。

    原来 putcomputeIfAbsent , 将元素放入 HashMap使用不同的方式;这是完全允许的,因为 Map 无论如何都没有任何顺序 - 这些元素无论如何最终都在同一个桶中,这是导入部分。所以一键测试你的代码,之前的测试代码被破坏了。

    如果您愿意,这甚至更有趣:
    HashMap::put将在 Linked 中添加元素时尚(直到 Tree 条目被创建),所以如果你有一个元素,所有其他元素将被添加,如:
    one --> next --> next ... so on.

    元素附加到 end of this queue当他们进入 put方法。

    另一方面 computeIfAbsent有点不同,它将元素添加到队列的开头。如果我们以上面的例子为例,首先 Xavier被添加。然后,当 Kenneth添加,成为第一个:
     Kenneth -> Xavier // Xavier was "first"

    Samuel添加后,它成为第一个:
     Samuel -> [Kenneth -> Xavier] 

    关于java-8 - 与流 API 交换实现后 Junit 测试失败,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55733916/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com