java - 在 Java 中优化历史字符串数组的代码

标签 java arrays optimization

我正在寻求优化代码方面的指导。我编写的代码适用于基于文本的游戏,您可以在命令栏中输入命令。我希望在界面中加入的一项功能是能够滚动浏览最近使用向上和向下箭头键输入的 100 个命令的历史记录,以便用户玩游戏时更加方便。

我设计了一个类,其中使用 String[] 将每个新条目存储在第二个位置 (Array[1]) 并将所有条目移回原处一个位置,而数组的第一个位置 (Array[0]) 只是一个空白的空字符串。该代码将数组初始化为具有 101 个值,以补偿第一个位置为空行。

当用户按该顺序输入 0 - 100 时,它应该给我相反的顺序(几乎像后进先出的情况,但存储最后 100 个值,而不是在它们出现后将其删除)被访问),并且由于 0 - 100 是 101 个值,因此最后一个值将被覆盖。

因此,向上滚动历史记录,它会给我 100, 99, 98, ..., 2, 1。如果我从列表中选择 50,那么它将是 50, 100, 99, 。 .., 3, 2.代码确实做到了这一点。

代码如下:

public class CommandHistory {
private String[] history;
private final int firstIndex = 1;
private static int currentIndex = 0;

/**
 * Default constructor, stores last 100 entries of commands plus the blank
 * entry at the first index
 */
public CommandHistory() {
    history = new String[101];
}

/**
 * Constructor with a capacity, stores the last (capacity) entries of
 * commands plus the blank entry at the first index
 * 
 * @param capacity
 *            Capacity of the commands history list
 */
public CommandHistory(int capacity) {
    history = new String[capacity + 1];
}

/**
 * Returns the size (length) of the history list
 * 
 * @return The size (length) of the history list
 */
private int size() {
    return history.length;
}

/**
 * Adds a command to the command history log
 * 
 * @param command
 *            Command to be added to the history log
 */
public void add(String command) {
    history[0] = "";
    if (!command.equals("")) {
        for (int i = firstIndex; i < size();) {
            if (history[i] == null) {
                history[i] = command;
                break;
            } else {
                for (int j = size() - 1; j > firstIndex; j--) {
                    history[j] = history[j - 1];
                }
                history[firstIndex] = command;
                break;
            }
        }
        currentIndex = 0;
    }
}

/**
 * Gets the previous command in the history list
 * 
 * @return The previous command from the history list
 */
public String previous() {
    if (currentIndex > 0) {
        currentIndex--;
    }
    return history[currentIndex];
}

/**
 * Gets the next command in the history list
 * 
 * @return The next command from the history list
 */
public String next() {
    if (currentIndex >= 0 && (history[currentIndex + 1] != null)) {
        currentIndex++;
    }
    return history[currentIndex];
}

/**
 * Clears the command history list
 */
public void clear() {
    for (int i = firstIndex; i < size(); i++) {
        history[i] = null;
    }
    currentIndex = 0;
}

/**
 * Returns the entire command history log
 */
public String toString() {
    String history = "";
    for (int i = 0; i < size(); i++) {
        history += this.history[i];
    }
    return history;
}
}

在我的界面类中,一旦用户在命令栏中输入内容并按 Enter 键,它将获取当前存储在栏中的文本,使用 add 方法将其添加到历史记录中,通过另一个类解析命令,然后将栏中的文本设置为空白。

按向上箭头调用下一个方法,向上滚动列表,按向下箭头调用上一个方法,向下滚动列表。

它似乎可以按照我希望的方式工作,但我想知道是否有某种方法可以优化此代码,甚至可能以完全不同的方式对其进行编码。我制作这个游戏是为了让自己练习 Java 并学习新的和更高级的东西,所以我很乐意听到任何关于如何做到这一点的建议。

最佳答案

对您问题的评论已经指出,您正在以某种方式试图通过实现标准 Java 类库在某种程度上已经提供的功能来重新发明轮子(请参阅 LinkedList/Queue 和 Arraylist)。但既然你说你想继续练习 Java,我想如果你尝试从头开始实现你自己的命令历史记录,那就完全没问题了。

以下是我的一些观察/建议:

1) 声明最终的第一个索引为 1 是没有必要的,也是非常违反直觉的。从默认索引 0 开始并在必要时添加相应的检查会很容易。

2) 忘记你的私有(private) size() 方法 - 它只是返回内部数组的长度(即初始容量+1)。相反,请考虑添加一个公共(public) size() 方法,该方法返回添加的命令的实际数量,并在添加新命令时在内部更新实际大小(请参阅 java.util.ArrayList 以供引用)。

3) 目前每次调用 add(String command) 都会设置history[0] = "",这是没有必要的。如果您希望第一个索引为“”,请在构造函数中设置它。这也是一个明显的迹象,表明从初始索引 0 而不是 1 开始可能会更好。

4) 一个小问题:在 add 方法中的“if (!command.equals(""))”对于这样一个专门的类来说可能没问题,但绝对应该在该方法的文档中对其进行注释。就我个人而言,我总是让调用类决定空的“”命令是否被认为有效。当 null 用作参数时,此方法还将引发未记录的 NullPointerException。考虑将其更改为“if (!””.equals(command))”,或者如果添加 null 则抛出 IllegalArgumentException。

5) 如果您在内部保留指向命令实际大小的指针,则 add 方法期间的“if (history[i] == null)”是完全不必要的 - 这实际上是一种特殊情况,只会是 true ,当第一个命令添加到命令历史记录中时(即,当它的实际大小 == 0 时)。

6) 如果您保留指向实际大小的指针,则在 add 方法实现中也没有必要有两个嵌套的 for 循环(请参见下面的示例)

7)我会重新考虑是否有必要在命令历史记录中保留指向当前索引的指针。就我个人而言,我会避免存储这样的指针,并将这些详细信息留给调用类 - 即删除前一个和下一个方法,并提供前向/后向迭代器和/或对可用命令索引的随机访问。有趣的是,当从命令历史记录类中删除此功能时,它实际上归结为 LinkedList 或 ArrayList 的实现 - 无论您采用哪种方式。因此,最终使用内置的 Java 集合之一实际上是一种可行的方法。

8)最后但同样重要的是,我会重新考虑在列表开头插入添加的命令是否有用 - 我相信将它们附加到末尾会更自然,例如ArrayList 可以。将命令添加到末尾将使每次调用 add() 期间所有当前命令的交换变得不必要...

以下是对您的类(class)的一些建议更改(未经真正测试...)

public class CommandHistory {
private String[] history;
private int size;
private static int currentIndex = 0;

/**
 * Default constructor, stores last 100 entries of commands plus the blank
 * entry at the first index
 */
public CommandHistory() {
    this(100);
}

/**
 * Constructor with a capacity, stores the last (capacity) entries of
 * commands plus the blank entry at the first index
 * 
 * @param capacity
 *            Capacity of the commands history list
 */
public CommandHistory(int capacity) {
    history = new String[capacity];
}

/**
 * Returns the size (length) of the history list
 * 
 * @return The size (length) of the history list
 */
public int size() {
    return size;
}

/**
 * Adds a command to the command history log
 * 
 * @param command
 *            Command to be added to the history log
 */
public void add(String command) {
    if (!"".equals(command)) {
        if (this.size < history.length) {
            this.size++;
        }
        for (int i = size-1; i >0; i--) {
            history[i] = history[i-1];
        }
        history[0] = command;
        currentIndex = 0;
    }
}

/**
 * Gets the previous command in the history list
 * 
 * @return The previous command from the history list
 */
public String previous() {
    if (currentIndex >= 0 && currentIndex < size-1) {
        currentIndex++;
    }
    return history[currentIndex];
}

/**
 * Gets the next command in the history list
 * 
 * @return The next command from the history list
 */
public String next() {
    if (currentIndex > 0 && currentIndex < size) {
        currentIndex--;
    }
    return history[currentIndex];
}

/**
 * Clears the command history list
 */
public void clear() {
    for (int i = 0; i < size; i++) {
        history[i] = null;
    }
    currentIndex = 0;
}

/**
 * Returns the entire command history log
 */
public String toString() {
    String history = "";
    for (int i = 0; i < size; i++) {
        history += this.history[i] + ", ";
    }
    return history;
}

}

嗯,我想我为此投入了太多时间,但我自己在这个过程中学到了很多东西 - 所以谢谢;-) 希望其中一些对您有用。

关于java - 在 Java 中优化历史字符串数组的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21559607/

相关文章:

Python Scipy 优化方法 : global optimization failed

java - java中数组求和的优化

java - AWS Elastic Beanstalk : access System variables

c# - 如何从抽象类创建对象?

java - Java 类链接解析步骤或初始化是否会导致加载其他解析的类?

有人可以帮我解释一下这段C代码吗?

C++ 二进制搜索函数不打印

optimization - 通过 Gulp 生成和优化 Webp

java - 从数据库检索字符串到 json 时遇到错误

java - 从数据库中保存和检索通过 jsp 给出的多个值