【问题标题】:Java: I can't for the life of me figure out why I'm getting a NullPointerException hereJava:我一辈子都想不通为什么我会在这里收到 NullPointerException
【发布时间】:2015-02-20 08:31:09
【问题描述】:

我正在创建一个基于控制台的 Evil Hangman 程序。不是在游戏开始时选择单词,而是通过选择包含用户输入的字母的单词逐渐缩小单词列表。

这是一个很常见的任务,所以我相信你以前听说过类似的事情。

这是规范,如果您需要更多说明。

Specification

编译所需的文件和客户端:

File

HangmanMain

这个特定类中有问题的方法是 record() 方法,这是迄今为止在这个赋值中最难编程的方法。 我观察到两个主要问题:

a) 有以下 NullPointerException 我无法弄清楚原因。它发生在将单词添加到列表中的行。据我所知,单词和列表都应该存在并且都已初始化。这不是列表不包含单词或列表未正确初始化的问题。它似乎只发生在第二次用户输入之后。

Exception in thread "main" java.lang.NullPointerException
at HangmanManager.record(HangmanManager.java:66)
at HangmanMain.playGame(HangmanMain.java:59)
at HangmanMain.main(HangmanMain.java:39)

b) NullPointerException 可能是在我之前尝试修复另一个问题时引起的。在 NullPointerException 发生之前,我在确定程序选择的单词没有遵循预期输出的原因时遇到了问题。不管我怎么做,程序在遍历结束时选择的单词总是“aa”。即使我故意选择“a”作为猜测,它应该有效地过滤掉“aa”作为选择,它仍然出现。

这是我目前的程序。

import java.util.*;
public class HangmanManager {
private String pattern;
private int length;
private int max;
private SortedSet<Character> guessesMade;
private Set<String> words;
private Set<String> currentWords;
private Map<String, Set<String>> patternMap;

public HangmanManager(List<String> dictionary, int length, int max){
    if (length < 1 || max < 0){
        throw new IllegalArgumentException();
    }
    this.length = length;
    this.max = max;
    words = new TreeSet<String>();
    for (String word : dictionary){
        if (word.length() == length){
            words.add(word);
        }
    }
    currentWords = new TreeSet<String>();
    guessesMade = new TreeSet<Character>();
    patternMap = new TreeMap<String, Set<String>>();
    pattern = "";
    for (int i = 0; i < length; i++){
        pattern += "- ";
    }

}
public Set<String> words(){
    return words;
}
public int guessesLeft(){
    return max - guessesMade.size();
}
public SortedSet<Character> guesses(){
    return guessesMade;
}
public String pattern(){
    if (words.isEmpty()){
        throw new IllegalArgumentException("There are no words.");
    }
    return pattern;
}

public int record(char guess){
    if (guessesLeft() < 1 || words.isEmpty()){
        throw new IllegalStateException();  
    }
    if (!words.isEmpty() && guessesMade.contains(guess)) { 
        throw new IllegalArgumentException();
    }
    guessesMade.add(guess);
    int largestOccurences = 0;
    for (String word: words){
        System.out.println(word);
        System.out.println(words.size());
        if (patternMap.containsKey(pattern)){   
            System.out.println("patternMap contains pattern");
            largestOccurences = generatePattern(word, guess);
            currentWords.add(word);
            currentWords = patternMap.get(pattern);
            patternMap.put(pattern, currentWords);          
        } else {
            currentWords.add(word);
            patternMap.put(pattern, currentWords);
        }
    }
    words = findFamily();
    return largestOccurences;
}
private Set<String> findFamily(){
    int maxSize = 0;
    Map <String, Integer> patternCount = new TreeMap<String, Integer>();
    for (String key : patternMap.keySet()){
        patternCount.put(key, patternMap.get(key).size());
            if (patternMap.get(key).size() > maxSize){
                maxSize = patternMap.get(key).size();
                pattern = key;
            } else if (patternMap.get(key).size() == maxSize){
                if (key.length() >= pattern.length()){
                    pattern = key;
                    maxSize = patternMap.get(key).size();
                }
            }
        }
    System.out.println("Current pattern: " + pattern);
    return patternMap.get(pattern);
}

private int generatePattern(String s, char guess) {
    int count = 0;
    pattern = "";
        for (int i = 0; i < length; i++){
            if (s.charAt(i) == guess){
                pattern += guess + " ";
                count++;
            } else {
                pattern += "- ";
            }
        }
    return count;
}
}

【问题讨论】:

  • 如果你能告诉我们HangmanMain.java中的第39行在哪里,你会很高兴
  • 这是人们不知道如何使用调试对 SO 的入侵
  • 我认为您的 word 在其中一次迭代中为空。由于 TreeSet 不允许空值,因此您将获得该 NPE
  • 用于初始化 HangmanManager 的字典不应包含 null 值。
  • 你能在第 66 行设置一个断点并检查什么是空的吗? (我认为你得到了 -1 分,因为家庭作业问题通常不被接受……但是,我们可以帮助你找出你的问题。)

标签: java list dictionary nullpointerexception set


【解决方案1】:

您的问题在于patternMap

 if (patternMap.containsKey(pattern))
    {   
        System.out.println("patternMap contains pattern");
        largestOccurences = generatePattern(word, guess);
        //=> generatePattern changes the global variable pattern, so it may 
        //not be contained in patternMap anymore

        currentWords.add(word);
        currentWords = patternMap.get(pattern);//since pattern was changed, 
                                               //patternMap return null and  
                                         //you get NullPointerException on 
                                         //the next iteration of the loop

        patternMap.put(pattern, currentWords);          
    }  

当您调用currentWords = patternMap.get(pattern); 时,您需要确保新更改的pattern 存在于patternMap 中。否则,你会得到null

【讨论】:

  • 感谢您的反馈!我实际上注意到程序中此时模式为空,但我认为它不相关,因为异常被抛出在未使用模式的行。第 66 行只使用了 currentWords 和 word。这无关紧要吗?
  • 您正在用currentWords = patternMap.get(pattern); 重新分配currentWords。这使得currentWords 为空。因此,当循环的下一个条目 for (String word: words) 被拉出时,currentWords 为空,并且您在第 66 行崩溃。
  • 哦,好吧,这很有道理。对不起。谢谢!
【解决方案2】:

在分配值之前检查 null.. currentWords = patternMap.get(pattern);

将其替换为 if(patternMap.get(pattern)!=null) currentWords = patternMap.get(pattern);

检查一下...如果您有任何此类分配,请进行空值检查..

祝你好运!

【讨论】:

    猜你喜欢
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    • 2015-11-22
    • 2021-06-18
    • 1970-01-01
    • 2019-09-09
    相关资源
    最近更新 更多