Just finished up a recent homework, but I know it could be more efficient. It reads two words from command line, ignores spaces and punctuation, and determines if they are anagrams. What I have is below; it’s fully functional as far as I can tell.
/**
* Find out if a string is an anagram of another string
*
*/
import java.util.Arrays;
public class Anagram
{
public static void main(String[] args)
{
if (args.length != 2)
System.out.println("You did not enter two words!");
else
printWords(args[0], args[1]);
}
// method to determine whether two strings have the same chars
public static boolean areAnagrams(String wordOne, String wordTwo)
{
// new strings for letters only
String ltrsOnlyOne = lettersOnly(wordOne);
String ltrsOnlyTwo = lettersOnly(wordTwo);
// convert strings to lowercase char arrays
char[] first = ltrsOnlyOne.toLowerCase().toCharArray();
char[] second = ltrsOnlyTwo.toLowerCase().toCharArray();
// sort char arrays using sort method
Arrays.sort(first);
Arrays.sort(second);
if (Arrays.equals(first, second))
return true;
else
return false;
}
public static String lettersOnly(String word)
{
int length = word.length();
StringBuilder end = new StringBuilder(length);
char x;
for (int i = (length - 1); i >= 0; i--) {
x = word.charAt(i);
if (Character.isLetter(x)) {
end.append(x);
}
}
return end.toString();
}
public static void printWords(String wordOne, String wordTwo)
{
boolean b = areAnagrams(wordOne, wordTwo);
if (b == true) {
System.out.println(wordOne + " is an anagram of "+ wordTwo);
}
if (b == false) {
System.out.println(wordOne + " is not an anagram of "+ wordTwo);
}
}
}
Bug fix:
lettersOnly‘s return value is lostYour
lettersOnlymethod does not modify its arguments in place, it returns the new strings. When you call it you need to do something with this return value. Otherwise you are simply calling it and throwing away the result.Dead code removal
In
main()you callsameCharswithout checking its return value. SincesameCharsdoesn’t modify its arguments in place or have any other side effects, this call is dead code and should be removed.Refactoring the
ifstatementsWhile your
ifstatements are correct, using==to compare againsttrueandfalseis not idiomatic. There is no need for explicit comparisons when you are using boolean values. It is shorter and reads better to simply omit the comparisons.Notice how
== falseis replaced by the equivalent!(NOT).Actually, there is no reason to repeat the call to
sameChars. Having code that looks so similar ought to raise a small alarm in your mind. "There should be a way to eliminate the duplicate code," you think. Ah yes, let's switch the secondifto anelse!Advanced
Along similar lines, you could simplify the following set of statements:
When the result of
equals()is true you return true. Otherwise when it is false you return false. If you think about it, you are effectively just returning whateverequalsreturned. You could actually eliminate theifandelseentirely and simply return the result ofequalsdirectly. Huh!This change is a bit more advanced than the earlier one. You might find this change a bit odd if you've never seen it before. But it's indeed equivalent to the four line version.
Loop reversal
Typically when programmers write
forloops they start at 0 and iterate up to some upper bound. Is there a reason you wrote your loop as a descending loop?Some programmers will loop backwards like this in a questionable attempt to be "more efficient". As in, they only perform the calculation
(length - 1)once, so it's slightly faster. Personally I consider this a waste of time and brain power.In fact, written backwards your
lettersOnlyfunction has the odd side effect of returning the strings in reverse order after it strips out the unwanted characters. It turns out this doesn't matter since you later sort the characters into alphabetical order. But this is a type of thing that could bite you later. It just so happened that you got away with the reversal because of the sorting. I would switch the loop to iterate in normal 0-to-n order: