HashMap 不能用循环初始化?从文本文件初始化 HashMap

HashMap cant be initialized with loop? Initialize HashMap from textfile

我是 java 的初学者,我正在尝试了解 HashMaps 的工作原理。我想将它用于我的谈话机器人,以便它可以识别例如用户正在提问的内容:

例如, 键 (String) 是用户提问的类别,值 (List) 是机器人将查找的问题。

我的问题是,当我在控制台中查看我的输出时,它看起来有效,但是当我调用 map.getKey() 时,我没有得到我期望的结果。

如果有帮助,我正在使用 Java 1.8。

我有一个包含以下内容的文本文件: “!”是类别

!first!
1good
1hello
1bye
!second!
2good
2hello
2bye

这是我的测试 class 文件,代码为:

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class InitHash
{

    public static void main(String[] args)
    {
        File file = new File(System.getProperty("user.dir") + "/data.txt");

        Map<String, List<String>> map = new HashMap<String, List<String>>();

        try
        {
            Scanner scan = new Scanner(file);
            String key = "";
            List<String> value = new ArrayList<String>();

            while (scan.hasNextLine())
            {
                String line = scan.nextLine();

                if (line.contains("!"))
                {
                    key = line;
                    key = key.replaceAll("!", "");
                    value.clear();
                } else
                {
                    value.add(line);
                }
                
                System.out.println(key + " , " + value);
                
                map.put(key, value);
            }
            
            scan.close();
            
            System.out.println(map.get("first")); //This prints the second category
            System.out.println(map.get("second"));
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

这是我在控制台中的输出:

first , []
first , [1good]
first , [1good, 1hello]
first , [1good, 1hello, 1bye]
second , []
second , [2good]
second , [2good, 2hello]
second , [2good, 2hello, 2bye]
[2good, 2hello, 2bye] //This is suppose to output [1good, 1hello, 1bye]
[2good, 2hello, 2bye]

感谢任何帮助和解释, 提前致谢!

在你的循环中,而不是这个:

value.clear();

每当你找到一个新的类别时初始化它,为了不修改以前值的内容(因为内存地址为两个键的列表共享,你只是将最后一个类别的值复制到所有以前的类别)。这将在添加元素的位置分配 value 一个新地址:

value = new ArrayList<String>();

如评论中所述,每次确定密钥已更改时,您都应该使用 ArrayList 的新实例,否则您只是为每个密钥重复使用相同的 ArrayList

以下示例演示了代码的修改版本,因此当代码检测到新键且前一个键不为空时,它会将 key 映射到 ArrayList.

然后它将创建一个 ArrayList 的新实例并将所有前面的值放入其中

File file = new File(System.getProperty("user.dir") + "/data.txt");
Map<String, List<String>> map = new HashMap<String, List<String>>();

try (Scanner scan = new Scanner(file);) {
    String key = "";
    List<String> value = new ArrayList<String>();

    while (scan.hasNextLine()) {
        String line = scan.nextLine();

        if (line.contains("!")) {
            if (!key.trim().isEmpty()) {
                map.put(key, value);
                System.out.println(key + " , " + value);
            }
            key = line;
            key = key.replaceAll("!", "");
            value = new ArrayList<String>();
        } else {
            value.add(line);
        }

    }
    if (!key.trim().isEmpty() && !value.isEmpty()) {
        map.put(key, value);
    }

    scan.close();

    System.out.println(map.get("first")); //This prints the second category
    System.out.println(map.get("second"));
} catch (Exception e) {
    e.printStackTrace();
}

现有代码可能会被重写为使用 Java 8 方法 Map::computeIfAbsent 以更简洁的方式在新键出现时创建 ArrayList 的新实例。

另外,最好使用try-with-resources确保输入文件的扫描器自动关闭。

Map<String, List<String>> map = new HashMap<>();
try (Scanner scan = new Scanner(file)) {
    String key = "";

    while (scan.hasNextLine()) {
        String line = scan.nextLine();

        if (line.contains("!")) {
            key = line.replace("!", "");
            map.computeIfAbsent(key, k -> new ArrayList<String>());
        } else {
            map.get(key).add(line);
        }
        
        System.out.println(key + " , " + map.get(key));
    }
    
    System.out.println(map.get("first")); //This prints the second category
    System.out.println(map.get("second"));
}

输出:

first , []
first , [1good]
first , [1good, 1hello]
first , [1good, 1hello, 1bye]
second , []
second , [2good]
second , [2good, 2hello]
second , [2good, 2hello, 2bye]
[1good, 1hello, 1bye]
[2good, 2hello, 2bye]