如何更正我的 Sorter 方法以允许更多用户输入?

How do I correct my Sorter methods to allow for more user input?

提问人:L4w1i3t 提问时间:9/6/2023 更新时间:9/6/2023 访问量:71

问:

我正在尝试为我的几个朋友构建一个排序算法,我现在正在为它做一个测试构建。最终,我将让它更加动态,但目前我只是让它接受用户输入一个人的名字以及他们输入的任何数字。但是,当我运行代码时,它要求输入名称,但随后它会在输入数值时终止。我已经处理了半个小时了,老实说,我有点难住了。

我的代码如下:

//Sorter.java
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Sorter {

    public static void dict() {

        // Create a dictionary
        Map<String, Range> dictionary = new HashMap<>();

        // Add groups and their corresponding value ranges
        dictionary.put("Family A", new Range(0, 10));
        dictionary.put("Family B", new Range(11, 20));
        dictionary.put("Family C", new Range(21, 30));

        // Retrieve the value range for a specific group
        Range rangea = dictionary.get("Family A");
        System.out.println("Value range for Family A: " + rangea.getStart() + " - " + rangea.getEnd());
        Range rangeb = dictionary.get("Family B");
        System.out.println("Value range for Family B: " + rangeb.getStart() + " - " + rangeb.getEnd());
        Range rangec = dictionary.get("Family C");
        System.out.println("Value range for Family C: " + rangec.getStart() + " - " + rangec.getEnd());

    }

    public static String getName() {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("Enter your name: ");
            if (scanner.hasNextLine()) {
                String nameInput = scanner.nextLine();
                System.out.println("Hello, " + nameInput + ".");
                return nameInput;
            } else {
                // handle no input available
                return null;
            }
        }
    }

/**
 * Prompts the user to enter a numerical value and prints the corresponding family group.
 */
    public static void counter() {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("Enter a numerical value: ");
            if (scanner.hasNextLine()) {
                String userInputString = scanner.nextLine();
                try {
                    int userInput = Integer.parseInt(userInputString);
                    String whatFamily = getGroup(userInput);
                    System.out.println("Family: " + whatFamily);
                } catch (NumberFormatException e) {
                    System.out.println("No Family LOL get rekt");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Determines the group based on the given value.
     *
     * @param  value  the value to be evaluated
     * @return        the group corresponding to the value
     */
    public static String getGroup(int value) {
        // Check if the value is less than 0
        if (value < 0) {
            return "Family A";
        }
        // Check if the value is within the range of Family A
        else if (value >= 1 && value <= 10) {
            return "Family A";
        }
        // Check if the value is within the range of Family B
        else if (value >= 11 && value <= 20) {
            return "Family B";
        }
        // Check if the value is within the range of Family C
        else if (value >= 21 && value <= 30) {
            return "Family C";
        }
        // Check if the value is greater than 30
        else if (value > 30) {
            return "Family C";
        }
        // Value is outside the range of any family
        else {
            return "No Family LOL get rekt";
        }
    }
}

class Range {
    private int start;
    private int end;

    public Range(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int getStart() {
        return start;
    }

    public int getEnd() {
        return end;
    }
}
//Exec.java

import java.util.HashMap;
import java.util.Map;

public class Exec {
    /**
     * Initializes a dictionary with groups and their corresponding value ranges.
     * Prints the value range for each group and prompts user input.
     *
     * @param  args  command line arguments
     */
    public static void main(String[] args) {

        // Prompt user input
        Sorter.getName();
        Sorter.dict();
        Sorter.counter();
    }
}
java 算法 排序 hashmap java.util.scanner

评论


答:

2赞 WJS 9/6/2023 #1

您的 try-with-resources 块会导致问题,因为 try with resources 会在完成后关闭打开(这不应该对控制台的扫描程序执行)。打开控制台扫描仪后,如果您在同一程序中关闭它,您将无法重新打开它。InputStream

请尝试以下操作以查看此行为。

try (Scanner scanner = new Scanner(System.in)) {
     System.out.print("Prompting for input:");
     if (scanner.hasNextLine()) {
         String s = scanner.nextLine();
         System.out.println(s);
     }         
 }
 try (Scanner scan = new Scanner(System.in)) {
     System.out.print("Prompting for input again: ");
     if (scan.hasNextLine()) {
         String s = scan.nextLine();
         System.out.println(s);
     }         
 }

只需使用一个扫描仪并将其传递给方法即可。并消除 try-with 资源块。

// Prompt user input
Scanner scanner = new Scanner(System.in);
Sorter.getName(scanner);
Sorter.dict();
Sorter.counter(scanner);
2赞 Reilas 9/6/2023 #2

"...当我运行代码时,它要求输入名称,但随后它会终止,因为它说要输入一个数值。..."

这是因为 scanner.hasNextLinecounter 方法中返回 false

删除条件后,scanner.nextLine 调用中将发生异常。

Exception in thread "main" java.util.NoSuchElementException: No line found
    at java.base/java.util.Scanner.nextLine(Scanner.java:1660)
    at Sorter.counter ...

这是因为 try-with-resources 语句正在关闭静态 System#in 流。

使用单个 Scanner 实例;将扫描仪作为 Sorter静态字段放置。
并且,在 getNamecounter 中使用此对象。

并且,在 nextLine 上使用 String#isBlank,而不是检查 hasNextLine

class Sorter {
    static Scanner scanner = new Scanner(System.in);

    public static void dict() {...}

    public static String getName() {
        System.out.print("Enter your name: ");
        String nameInput = scanner.nextLine();
        if (!nameInput.isBlank()) {
            System.out.println("Hello, " + nameInput + ".");
            return nameInput;
        } else {
            // handle no input available
            return null;
        }
    }

    public static void counter() {
        System.out.print("Enter a numerical value: ");
        String userInputString = scanner.nextLine();
        try {
            if (userInputString.isBlank()) throw new Exception(); 
            int userInput = Integer.parseInt(userInputString);
            String whatFamily = getGroup(userInput);
            System.out.println("Family: " + whatFamily);
        } catch (NumberFormatException e) {
            System.out.println("No Family LOL get rekt");
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
...
}

建议封装 LinkedHashMap 类,以便为 Range 对象提供功能。

class RangeMap<K, V extends Range> extends LinkedHashMap<K, Range> {
    Range put(K key, int i, int n) {
        return super.put(key, new Range(i, n));
    }

    Range get(int i, int n) {
        return super.get(new Range(i, n));
    }

    AbstractMap.SimpleEntry<K, Range> find(int x) {
        Range copy;
        for (Map.Entry<K, Range> e : entrySet()) {
            copy = e.getValue();
            if (x >= copy.getStart() && x <= copy.getEnd())
                return new SimpleEntry<>(e.getKey(), e.getValue());
        }
        return null;
    }
}

现在,您可以重构 getGroup 方法。
您需要增加字典的范围并切换上下文。

class Sorter {
    static Scanner scanner = new Scanner(System.in);
    // Create a dictionary
    static RangeMap<String, Range> dictionary = new RangeMap<>();
...
    public static String getGroup(int value) {
        AbstractMap.SimpleEntry<String, Range> r = dictionary.find(value);
        if (r != null) return r.getKey();
        return "No Family LOL get rekt";
    }
...
}

此外,您可以修改 dict 方法。

public static void dict() {
    // Add groups and their corresponding value ranges
    dictionary.put("Family A", 0, 10);
    dictionary.put("Family B", 11, 20);
    dictionary.put("Family C", 21, 30);

    // Retrieve the value range for a specific group
    Range range;
    for (Map.Entry<String, Range> e : dictionary.entrySet()) {
        range = e.getValue();
        System.out.printf("Value range for %s: %d - %d%n",
                          e.getKey(), range.start(), range.end());
    }
}

最后,您可以利用 Range的记录。 这将强制名称 getStart 开始getEnd 结束

record Range(int start, int end) { }