我正在学习Java,这是一个程序的解决方案,它将读取0到99范围内的两个数字并将它们相乘。输入数字是用自然语言给出的,例如对于输入32-10,它应该返回320。我已经尽力了。请有人回顾一下,如果有的话,可以提出改进建议吗?
package assignments;
import java.util.*;
public class NaturalLanguageMultiply {
private static final Map<String, Integer> numericValues = new HashMap<String, Integer>();
private static final String WORD_SEPARATOR = "-";
static {
numericValues.put("zero", 0);
numericValues.put("one", 1);
numericValues.put("two", 2);
numericValues.put("three", 3);
numericValues.put("four", 4);
numericValues.put("five", 5);
numericValues.put("six", 6);
numericValues.put("seven", 7);
numericValues.put("eight", 8);
numericValues.put("nine", 9);
numericValues.put("ten", 10);
numericValues.put("eleven", 11);
numericValues.put("tweleve", 12);
numericValues.put("thirteen", 13);
numericValues.put("fourteen", 14);
numericValues.put("fifteen", 15);
numericValues.put("sixteen", 16);
numericValues.put("seventeen", 17);
numericValues.put("eighteen", 18);
numericValues.put("nineteen", 19);
numericValues.put("twenty", 20);
numericValues.put("thirty", 30);
numericValues.put("forty", 40);
numericValues.put("fifty", 50);
numericValues.put("sixty", 60);
numericValues.put("seventy", 70);
numericValues.put("eighty", 80);
numericValues.put("ninety", 90);
}
private static int wordToNumber(String word) {
String[] tokens = word.split(WORD_SEPARATOR);
int number = 0;
for(String token : tokens) {
Integer numericValue = numericValues.get(token);
if(numericValue == null) {
throw new IllegalArgumentException("unknown token " + token + " in word " + word);
}
number += numericValue;
}
return number;
}
public static void main(String[] args) {
if(args.length < 2) {
System.out.println("argument missing");
System.exit(1);
}
try {
int firstNumber = wordToNumber(args[0]);
int secondNumber = wordToNumber(args[1]);
System.out.format("%d%n", firstNumber * secondNumber);
System.exit(0);
} catch(Exception e) {
System.out.println(e.getMessage());
System.exit(1);
}
}
}发布于 2017-02-10 10:10:09
我不知道为什么你的问题至今仍未得到回答。但我想“练习”往往不太受关注,因为这个练习似乎是很基本的。别误会我。每个人都必须经历一些基本的事情。
所以关键是你找到了一个问题的解决方案。到目前为止你做得很好。但我希望你继续下去,因为这只是表面而已。下面是每个程序员必须经历的事情。
关键是,所提供的代码只能在第1、2和3点下进行判断。由于我不知道您深入java编程语言的深度,也许是时候应用面向对象或函数式编程范例了。
由于您的代码目前是程序性的,我建议以一种更面向对象的方式来制定代码。
静态修饰符并不是整体上的坏(例如常量),但是对于方法,它会阻碍您从OO机制“多态”中获益。
尝试用对象来构造代码。从这里开始,删除除main-方法以外的所有方法的所有静态修饰符。为您的类"NaturalLanguageMultiply“引入一个构造函数。传入Array,进行验证,并将其存储在局部变量中。
这一点都没有意义,因为如果程序结束,每个程序都将与退出代码0一起离开。这是一个不必要的声明。
我建议只有一个异常处理的概念。如果您想通过调用System.exit(.)来促进程序的执行失败然后在程序的最后声明中这样做。在内部,您应该依赖异常。因此,您的参数验证不应该退出JVM,而应该抛出一个IllegalArgumentException。
目前,您捕获“异常”。我建议明确地捕获预期的异常。这有助于您返回可区分的退出代码。
此外,在代码中的任意位置避免System.out.println,以促进异常。这将导致冗余代码遍布各地。在你要处理的异常情况下推广它们。
。
引入一个名为getResult()的方法来进行乘法。
正如注释中所建议的那样,正确命名事物将有助于其他人阅读您的代码。我会将常量名从"WORD_SEPARATOR“更改为"TOKEN_SEPARATOR”,并将"args“重命名为”word“。这对我来说是有意义的。你有两个词都是说出来的数字。一个单词通过这些标记的分隔符划分为令牌。也许你也可以把“单词”重命名为"spokenNumbers“,把"word”重命名为"spokenNumber“。但我想我已经办到了。
public class NaturalLanguageMultiply {
private static final Map<String, Integer> numericValues = new HashMap<String, Integer>();
private static final String TOKEN_SEPARATOR = "-";
static {
numericValues.put("zero", 0);
numericValues.put("one", 1);
numericValues.put("two", 2);
...
numericValues.put("ninety", 90);
}
private String[] words;
NaturalLanguageMultiply(String[] words) {
if(words.length < 2) {
throw new IllegalArgumentException("argument missing");
}
this.words = words;
}
private int wordToNumber(String word) {
String[] tokens = word.split(TOKEN_SEPARATOR);
int number = 0;
for (String token: tokens) {
Integer numericValue = numericValues.get(token);
if(numericValue == null) {
throw new IllegalArgumentException("unknown token " + token + " in word " + word);
}
number += numericValue;
}
return number;
}
private int getResult() {
int firstNumber = wordToNumber(words[0]);
int secondNumber = wordToNumber(words[1]);
return firstNumber * secondNumber;
}
public void main(String[] args) {
try {
int result = new NaturalLanguageMultiply(args).getResult();
System.out.format("%d%n", result);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
System.exit(1);
} catch (Exception e) {
System.out.println(e.getMessage());
System.exit(2);
}
}
}您的解决方案分析和解释传入的数据和处理计算。这最好用状态模式和解释器模式来解决。这是一个先进的技术,当你感到准备好的时候,你应该想到它。
发布于 2017-02-11 16:07:49
当前的方法接受像twenty-twelve这样的字符串来表示32,这可能是不可取的。您可能希望验证第一个或第二个令牌是否可以与另一个令牌组合,例如,拒绝twenty-twelve,因为twelve不能是第二个令牌,并接受thirty-two。
例如,您可以拥有一个NumberToken类:
public class NumberToken {
private final int value;
private final String text;
private final Position position;
public NumberToken(int value, String text, Position position) {
// constructor
}
// getters...
}
public enum Position {
FIRST, SECOND, BOTH;
}Position的枚举值允许我们验证令牌如何与其他令牌组合。例如:
public NumberToken two = new NumberToken(2, "two", Position.BOTH);
public NumberToken twelve = new NumberToken(12, "twelve", Position.FIRST);
public NumberToken twenty = new NumberToken(20, "twenty", Position.FIRST);
public NumberToken thirty = new NumberToken(30, "thirty", Position.FIRST);首先,可以进行的验证如下:
Position.FIRST和Position.SECOND必须位于各自的位置。Position.BOTH不能与另一个Position.BOTH组合。您还应该考虑边缘情况,比如如何拒绝twelve-two (例如,Position.FIRST_ONLY for twelve之类的新值?)。
这种方法的一个优点是,使用新的基于流的处理很容易生成查找Map:
private static final Map<String, NumberToken> LOOKUP =
Arrays.stream(one, two, /* ... */ ninety)
.collect(Collectors.toMap(NumberToken::getText, Function.identity()));错误输出应该转到System.err而不是System.out:
try {
// ...
// Below System.exit(int) is unnecessary, status will be 0 by default
// System.exit(0);
} catch(Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}从Java 7开始,您可以在变量声明中使用<>来表示所需的泛型类型。,如下所示:
private static final Map<String, Integer> numericValues = new HashMap<>();https://codereview.stackexchange.com/questions/154877
复制相似问题