具有多个值的 HashMap get.key() 错误

HashMap with multiple values get.key() error

import java.util.*;

class Student{

    final String name;
    final String gender;
    public String number;

     static Map<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
     static ArrayList<String> nameandNumber = new ArrayList<>();




    Student(String number, String name, String gender) {
        this.name = name;
        this.gender = gender;
        this.number = number;


        nameandNumber.add(this.name);
        nameandNumber.add(this.number);

        hm.put(this.gender,nameandNumber);
    }

    void getPersonByGender() {
        String[] Liste = hm.get("Man").toArray(new String[0]);
        for (int i = 0; i < Liste.length - 1; i += 2) {
            System.out.println(Liste[i] + "\t<------>\t" + Liste[i + 1]);
        }
    }
}

大家好,我正在创建一个class,这个class会return给我10个学生信息,我会给出(根据男女差异)。当我尝试使用 getPersonByGender 的函数时,此函数会为我提供所有学生。

static ArrayList<String> nameandNumber = new ArrayList<>();

new 很有用:计算代码调用的次数 new ArrayList。这是一个相当简单的答案:一次。对于您的整个程序。

如果你只调用一次new,那意味着只有一个列表。在整个系统中。

难怪:这个:

nameandNumber.add(this.number);

您的应用程序的单个 'run' 被调用 10 次(因为有 10 个学生)。因此,您拥有的那个列表必须因此将所有这些数字加在一起 ​​- 这就是为什么您会看到所有数据。

不幸的是,您的代码包含多层糟糕的设计决策。

您可以 'fix' 解决问题(但它仍然是难以阅读的脆弱代码),或者您可以 'fix' 设计(这需要更多工作)。

解决问题

您想要为每个学生调用 new ArrayList,而不是所有学生共享的 1 个列表,这显然是行不通的。摆脱那个 static 单个数组列表,而是每次都创建一个:

Student(String number, String name, String gender) {
    this.name = name;
    this.gender = gender;
    this.number = number;

    var nameandNumber = new ArrayList<String>();
    nameandNumber.add(this.name);
    nameandNumber.add(this.number);

    hm.put(this.gender, nameandNumber);
}

例如,现在您在一个 运行 程序中调用 new ArrayList 的正确次数。

但是您在这里仍然遇到麻烦 - 因为您决定使用 List 来表示单个想法(学生),所以您自己感到困惑:给定的性别映射到 多名 名学生。鉴于单个学生由 List<String> 表示,多个学生将由 List<List<String>> 表示,哦,这变得非常复杂,非常快。

我们可以插手进一步解决这个问题,但让我们退后一步,改为修复您的设计!

修改设计

更一般地说,java 的类型系统是高度名义化的:类型有名称,名称越具有描述性越好。

Student 是一个比 List<String> 更好、更清晰的名字 。您的代码的 reader 应该如何知道那些 List<String> 对象专门用于恰好包含 2 个字符串,第一个是学生的姓名,第二个是他们的学号?它没有在任何地方这么说。如果你搞砸了,你不会得到任何类型的编译器错误。

一个类型,就在那里,正确描述了这个概念:Student!

那么为什么不替换这个错误的代码:

static Map<String, ArrayList<List<String>>> hm = new HashMap<String, ArrayList<List<String>>>();

有了这个大大改进的代码:

static Map<String, List<Student>> genderMap = new HashMap<>();

它有各种改进:

  • 它有一个专有名称。 hm 没有任何意义。
  • 它使用 <> 来缩短 - 你不需要重复那些东西。
  • 它编码为原理(List)而不是具体的class。
  • 它使用名义类型 - 这将性别字符串映射到学生列表。而且代码读起来一样,很好。

放在一起:

class Student {
    final String name;
    final String gender;
    final String number;

    static Map<String, List<Student>> genderMap = new HashMap<>();

    Student(String number, String name, String gender) {
        this.name = name;
        this.gender = gender;
        this.number = number;

        List<Student> studentsForThisGender = genderMap.get(gender);
        if (studentsForThisGender == null) {
          // There is no list yet; we need to make one.
          genderMap.put(gender, studentsForThisGender = new ArrayList<>());
        }
        studentsForThisGender.add(this);
    }

    static void getPersonByGender() {
        Student[] liste = genderMap.get("Man").toArray(new Student[0]);
        for (Student student : liste) {
            System.out.println(student.name + "\t<------>\t" + student.number);
        }
    }
}

注:

  • getPersonByGender 现在是 static - 这是您对 'students' 而不是任何特定学生的概念所做的事情。
  • 我们打印 student.name 文件本身,而不是这个模糊的“打印列表[0] - 你只需要知道那是名字”。
  • 我们解决了您所在的问题 list-confused。
  • 如果您在 java 研究中取得更进一步的进展,那么 'get the list of students for a given gender, and make a new list if neccessary' 可以更简洁。最后 4 行可以简化为:
genderMap.computeIfAbsent(gender, () -> new ArrayList<>()).add(this);

但我敢打赌,您的 java 课程中还没有涵盖语法以及那里发生的事情。