patternjavaMinor
Natural language multiply
Viewed 0 times
multiplynaturallanguage
Problem
I am learning Java and this is my solution for a program that will read two numbers in the range of 0 to 99 and multiply them. Input numbers are given in natural language e.g. for input thirty-two ten it should return 320. I have tried to do my best. Could someone please review this and suggest improvements, if any?
```
package assignments;
import java.util.*;
public class NaturalLanguageMultiply {
private static final Map numericValues = new HashMap();
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 " +
```
package assignments;
import java.util.*;
public class NaturalLanguageMultiply {
private static final Map numericValues = new HashMap();
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 " +
Solution
General
I do not know exactly why your question remains unanswered till now. But I guess "exercises" tend to have less attention as this exercise seems to be really basic. Do not get me wrong. Everybody had to go through basic things.
So the point is that you found a solution to a problem. And so far you did very well. But I want encourage you to keep on going as this is only the surface. Here are the things every programmer has to go through.
-
Learn the theory of sequence, selection and iteration
-
Train your algorithmic thinking by solving problems with the elements of 1. in a programming language of your choice by increasing difficulty
-
Get familiar with the language mechanisms
-
Apply programming paradigms like functional or object-oriented programming
-
Formalize you code fragments by learning the currently identified 26 design patterns and learn to to apply them in the correct situations
-
Organize your code by following the correct semantic of each code fragment and learn and apply the SOLID principles as they guide you through the jungle of design decisions
-
Learn the restrictions of the language you use for a problem. Maybe in another language you are able to express the solution in another way that is more elegant.
The point is that the code provided can only be judged under point 1, 2 and 3. And there your are on a good way. As I do not know how deep you dived into the java programming language maybe it is time to apply the object-oriented or functional programming paradigm.
As your code currently is procedural I suggest to formulate your code in a more object-oriented way.
Suggestions
Reduce static elements
The static modifier is not overall bad (e.g. constants) but for methods it hinders you to benefit from the OO mechanism "polymorphism".
Introduce OO
Try to formulate your code with objects. To start here remove all static modifiers from all methods but the the main-method. Introduce a constructor for your class "NaturalLanguageMultiply". Pass in the arg-Array make the validation and store it in a local variable.
Do not exit with System.exit(0);
This does not make sense at all as every program will leave with the exit code 0 if the program ends. It is a needless statement.
Exception handling
I suggest to have a single concept of exception handling. If you want to promote execution failure of a program by calling System.exit(...) then do this in the final statement in your program. Internally you should rely on exceptions. So your argument validation should not exit the JVM but throwing an IllegalArgumentException.
Currently you catch "Exception". I suggest to catch expected Exceptions explicitly. This helps you to return distinguishable exit codes.
Furthermore avoid System.out.println at arbitrary locations in your code to promote exceptions. This will cause redundant code spread all over the place. Promote the exceptions where you are going to handle them.
Provide a calculation-method
Introduce a method called getResult() to do the multiplication.
Naming
As mentined in the comments naming things properly will help others to read your code. I would change the constant name from "WORD_SEPARATOR" to "TOKEN_SEPARATOR" and renaming "args" into "words". This how it makes sense to me. You have two words that are both spoken numbers. And one word is partitioned into token by a separator of those tokens. Maybe you can also rename "words" into "spokenNumbers" and "word" into "spokenNumber". But I think I made case.
Code
```
public class NaturalLanguageMultiply {
private static final Map numericValues = new HashMap();
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).getR
I do not know exactly why your question remains unanswered till now. But I guess "exercises" tend to have less attention as this exercise seems to be really basic. Do not get me wrong. Everybody had to go through basic things.
So the point is that you found a solution to a problem. And so far you did very well. But I want encourage you to keep on going as this is only the surface. Here are the things every programmer has to go through.
-
Learn the theory of sequence, selection and iteration
-
Train your algorithmic thinking by solving problems with the elements of 1. in a programming language of your choice by increasing difficulty
-
Get familiar with the language mechanisms
-
Apply programming paradigms like functional or object-oriented programming
-
Formalize you code fragments by learning the currently identified 26 design patterns and learn to to apply them in the correct situations
-
Organize your code by following the correct semantic of each code fragment and learn and apply the SOLID principles as they guide you through the jungle of design decisions
-
Learn the restrictions of the language you use for a problem. Maybe in another language you are able to express the solution in another way that is more elegant.
The point is that the code provided can only be judged under point 1, 2 and 3. And there your are on a good way. As I do not know how deep you dived into the java programming language maybe it is time to apply the object-oriented or functional programming paradigm.
As your code currently is procedural I suggest to formulate your code in a more object-oriented way.
Suggestions
Reduce static elements
The static modifier is not overall bad (e.g. constants) but for methods it hinders you to benefit from the OO mechanism "polymorphism".
Introduce OO
Try to formulate your code with objects. To start here remove all static modifiers from all methods but the the main-method. Introduce a constructor for your class "NaturalLanguageMultiply". Pass in the arg-Array make the validation and store it in a local variable.
Do not exit with System.exit(0);
This does not make sense at all as every program will leave with the exit code 0 if the program ends. It is a needless statement.
Exception handling
I suggest to have a single concept of exception handling. If you want to promote execution failure of a program by calling System.exit(...) then do this in the final statement in your program. Internally you should rely on exceptions. So your argument validation should not exit the JVM but throwing an IllegalArgumentException.
Currently you catch "Exception". I suggest to catch expected Exceptions explicitly. This helps you to return distinguishable exit codes.
Furthermore avoid System.out.println at arbitrary locations in your code to promote exceptions. This will cause redundant code spread all over the place. Promote the exceptions where you are going to handle them.
Provide a calculation-method
Introduce a method called getResult() to do the multiplication.
Naming
As mentined in the comments naming things properly will help others to read your code. I would change the constant name from "WORD_SEPARATOR" to "TOKEN_SEPARATOR" and renaming "args" into "words". This how it makes sense to me. You have two words that are both spoken numbers. And one word is partitioned into token by a separator of those tokens. Maybe you can also rename "words" into "spokenNumbers" and "word" into "spokenNumber". But I think I made case.
Code
```
public class NaturalLanguageMultiply {
private static final Map numericValues = new HashMap();
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).getR
Code Snippets
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);
}
}
}Context
StackExchange Code Review Q#154877, answer score: 4
Revisions (0)
No revisions yet.