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

Java HashMap不能用循环初始化?从文本文件初始化HashMap,java,file,hashmap,Java,File,Hashmap,我是java的初学者,我正在努力理解HashMaps是如何工作的。我想将其用于我的talk bot,以便它能够识别用户提出的问题: 比如说,, 键(字符串)是用户提问的类别,值(列表)是机器人将查找的问题 我的问题是,当我在控制台中查看我的输出时,它看起来像是工作的,但当我调用map.getKey()时,我并没有得到我期望的结果 如果有帮助的话,我正在使用Java1.8 我有一个包含以下内容的文本文件: “!”是类别 !first! 1good 1hello 1bye !second! 2goo

我是java的初学者,我正在努力理解HashMaps是如何工作的。我想将其用于我的talk bot,以便它能够识别用户提出的问题:

比如说,, 键(字符串)是用户提问的类别,值(列表)是机器人将查找的问题

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

如果有帮助的话,我正在使用Java1.8

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

!first!
1good
1hello
1bye
!second!
2good
2hello
2bye
这是我的测试类文件,包含以下代码:

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();
        }
    }
}
感谢您的帮助和解释,
提前谢谢

在循环中,而不是:

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


value=newarraylist()

如注释中所述,每次确定密钥已更改时,都应使用
ArrayList
的新实例,否则您只需对每个密钥重新使用相同的
ArrayList

下面的示例演示了代码的修改版本,因此当代码检测到新密钥,并且前一个密钥不为空时,它会将
密钥
映射到
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();
}
File File=new文件(System.getProperty(“user.dir”)+“/data.txt”);
Map Map=newhashmap();
尝试(扫描仪扫描=新扫描仪(文件);){
字符串键=”;
列表值=新的ArrayList();
while(scan.hasNextLine()){
String line=scan.nextLine();
如果(第行包含(!”){
如果(!key.trim().isEmpty()){
map.put(键、值);
System.out.println(键+“,”+值);
}
键=行;
key=key.replaceAll(“!”,“”);
值=新的ArrayList();
}否则{
增值(行);
}
}
如果(!key.trim().isEmpty()&&!value.isEmpty()){
map.put(键、值);
}
scan.close();
System.out.println(map.get(“first”);//这将打印第二个类别
System.out.println(map.get(“第二”);
}捕获(例外e){
e、 printStackTrace();
}

当新键以更简洁的方式出现时,可以重写现有代码,以使用Java 8方法创建
ArrayList
的新实例

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

Map Map=newhashmap();
尝试(扫描仪扫描=新扫描仪(文件)){
字符串键=”;
while(scan.hasNextLine()){
String line=scan.nextLine();
如果(第行包含(!”){
键=行。替换(“!”,“”);
computeIfAbsent(key,k->newArrayList());
}否则{
map.get(key)、add(line);
}
System.out.println(key+”,“+map.get(key));
}
System.out.println(map.get(“first”);//这将打印第二个类别
System.out.println(map.get(“第二”);
}
输出:

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]

地图中的每个条目都应该使用一个唯一的
列表实例
,否则,所有键都共享同一个
列表实例
。我也认为只有把钥匙放在地图上,当钥匙被认为已经改变了,你的意思是我必须创建两个列表吗?我试图在键更改时将列表放入映射,但“first”键返回null。也许我完全弄错了。对不起,我的英语不是最好的。请查看张贴的示例。您应该只有一个
ArrayList
的实例,但每次键更改时,您都应该创建一个新实例(并将其分配给
),以便可以向其添加新值现在我明白了!非常感谢!
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]