Finding words of different lengths given six letters I'm trying to find all the 3, 4, 5, and 6 letter words given 6 letters.  I am finding them by comparing every combination of the 6 letters to an ArrayList of words called sortedDictionary.  I have worked on the code a good bit to get it to this point.

I tested how many six letter words are checked and got 720 which is good because 6*5*4*3*2*1=720 which means I am not checking any words twice.  I can't make it faster by getting rid of duplicate checks because I have already gotten rid of them all.  

Can I still make this faster?

Note that sortedDictionary only contains about 27 hundred words. 

for(int l1 = 0; l1 &lt; 6; l1++){
    for(int l2 = 0; l2 &lt; 6; l2++){
        if(l2 != l1)
            for(int l3 = 0; l3 &lt; 6; l3++){
                if(l3 != l1 &amp;&amp; l3 != l2){
                    if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
                        anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);
                    for(int l4 = 0; l4 &lt; 6; l4++){
                        if(l4 != l1 &amp;&amp; l4 != l2 &amp;&amp; l4 != l3){
                            if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]))
                                anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]);
                            for(int l5 = 0; l5 &lt; 6; l5++){
                                if(l5 != l1 &amp;&amp; l5 != l2 &amp;&amp; l5 != l3 &amp;&amp; l5 != l4){
                                   if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]))
                                       anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]);
                                   for(int l6 = 0; l6 &lt; 6; l6++){
                                       if(l6 != l1 &amp;&amp; l6 != l2 &amp;&amp; l6 != l3 &amp;&amp; l6 != l4 &amp;&amp; l6 != l5)
                                           if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]+anagramCharacters[l6]))
                                               anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]+anagramCharacters[l4]+anagramCharacters[l5]+anagramCharacters[l6]);
                                    }   
                                }
                            }   
                        }
                    }
                }
            }
    }
}


My solution, still probably not the best written code but it reduce the loading time from about 1-2 seconds to nearly instant (no noticeable wait time; didn't actually test how long it was).

for(int i = 0; i &lt; sortedDictionary.size(); i++){
    for(int index = 0; index &lt; anagram.length(); index++)
        anagramCharacters[index] = anagram.charAt(index);
    forloop:
    for(int i2 = 0; i2 &lt; sortedDictionary.get(i).length(); i2++){
        for(int i3 = 0; i3 &lt; anagramCharacters.length; i3++){
            if(sortedDictionary.get(i).charAt(i2) == anagramCharacters[i3]){
                anagramCharacters[i3] = 0;
                break;
            }
            else if(i3 == anagramCharacters.length-1)
                break forloop;
        }
        if(i2 == sortedDictionary.get(i).length()-1)
            anagram_words.add(sortedDictionary.get(i));
    }
}
Before I get started I have to say: Thank you for coming here. Mess of Java For Loops is almost an understatement. Now, let's get working, shall we?

In the below answer I assume that sortedDictionary and anagram_words is both of type List&lt;String&gt;. I also assume that anagramCharacters is of type char[].

Code duplication

Start by identifying which parts of the code looks similar, and create some methods to reduce code duplication

Code like this is repeated several times:

if(sortedDictionary.contains(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]))
     anagram_words.add(""+anagramCharacters[l1]+anagramCharacters[l2]+anagramCharacters[l3]);


This can be extracted to a method: addWord() (Note that the below method is not optimized for what it is doing, it is mainly so that you are able to understand what it does better).

private void addWord(char... chars) {
    String string = "";
    for (char ch : chars) string += ch; // Create a strings of the chars
    if (sortedDictionary.contains(string))
        anagram_words.add(string);
}


So instead of repeatedly writing

if (sortedDictionary.contains(....)) anagram_words.add(...)


we simply call a method:

addWord(anagramCharacters[l1], anagramCharacters[l2], anagramCharacters[l3]);


Variables with index

Whenever you find yourself using variable names that contains numbered values, such as l1, l2, l3, l4, STOP and think "Would an array be useful here?". Creating an int[] letters is far more flexible than using the multiple variables l1, l2, l3

If all the l-variables are instead inside the letters array, some things can be simplified further at the moment: 


This:

if(l4 != l1 &amp;&amp; l4 != l2 &amp;&amp; l4 != l3)


would become

if(letters[3] != letters[0] &amp;&amp; letters[3] != letters[1] &amp;&amp; letters[3] != letters[2])

This:

if(letters[3] != letters[0] &amp;&amp; letters[3] != letters[1] &amp;&amp; letters[3] != letters[2])


can become a method

private boolean lastLetterDifferent(int index) {
    for (int i = 0; i &lt; index; i++) {
        if (letters[i] == letters[index]) return false;
    }
    return true;
}

The previous call we made to addWord only needs to contain the number of indexes to check instead of each and every char.

private void addWord(int numberOfChars) {
    String string = "";
    for (int i = 0; i &lt; numberOfChars; i++) string += anagramCharacters[letters[i]]; // Create a strings of the chars
    if (sortedDictionary.contains(string))
        anagram_words.add(string);
}



So now that's done, what remains now?

After doing the above refactoring, here is what's left:

for(letters[0] = 0; letters[0] &lt; 6; letters[0]++){
    for(letters[1] = 0; letters[1] &lt; 6; letters[1]++) {
        if(lastLetterDifferent(1)) {
            for(letters[2] = 0; letters[2] &lt; 6; letters[2]++) {
                if(letters[2] != letters[0] &amp;&amp; letters[2] != letters[1]) {
                    addWord(3);
                    for(letters[3] = 0; letters[3] &lt; 6; letters[3]++) {
                        if (lastLetterDifferent(3)) {
                            addWord(4);
                            for(letters[4] = 0; letters[4] &lt; 6; letters[4]++){
                                if (lastLetterDifferent(4)) {
                                    addWord(5);
                                    for(letters[5] = 0; letters[5] &lt; 6; letters[5]++){
                                        if (lastLetterDifferent(5)) {
                                            addWord(6);
                                        }
                                    }   
                                }
                            }   
                        }
                    }
                }
            }
        }
    }
}


That looks a lot cleaner, but how flexible is this? What if we want to use an 8-letter word, or a 12-letter word? NO, you should NOT continue this pattern and add more for-loops! So what other alternative is there? Recursive methods, my friend!

To do this, we need a couple of helper methods. You mentioned the number 720. It just so happens that 720 equals 6 factorial. So let's create a factorial method.

public static int fact(int x) {
    if (x &lt; 0) throw new IllegalArgumentException("x cannot be negative: " + x);
    if (x &lt;= 1) return 1;
    return x * fact(x - 1);
}


This is a recursive because it calls itself on some occasions. More precisely, when x &gt;= 2. Recursive methods are fun, so let's create another one!

public static &lt;E&gt; List&lt;E&gt; permutationI(List&lt;E&gt; values, int iteration) {
    if (values.size() == 0)
        return new ArrayList&lt;E&gt;();
    List&lt;E&gt; list = new ArrayList&lt;E&gt;(values.size());
    int divisor = fact(values.size() - 1);
    int pos = iteration / divisor; // Pick an index depending on the iteration value
    list.add(values.remove((int)pos)); // Remove from one list and add to another
    list.addAll(permutationI(values, iteration % divisor)); // Call method recursively to get all the elements
    return list;
}


Every time this method is called, it picks an index in the values list depending on the value of iteration. Then it gets the element for that index from the values list, removes that element from the values list and adds it to the list called list (which will be the methods result. Then this method calls itself to add all the remaining elements for the current iteration.

Putting it together:

We will need one more utility method to convert from a List of characters to a String (again, this method is not fully optimized. There are plenty of faster ways to do this).

public String charListToString(List&lt;Character&gt; list) {
    String result = "";
    for (Character ch : list) {
        result += ch;
    }
    return result;
}


And now, the final touch to use all this recursive-ness:

List&lt;Character&gt; indexes = new ArrayList&lt;Character&gt;();
for (char ch : anagramCharacters)
    indexes.add(ch); // Build a list of the characters in our original word
int totalPermutations = fact(indexes.size());
for (int i = 0; i &lt; totalPermutations; i++) {
    // Since permutationI modifies the list we send, we copy the list
    List&lt;Character&gt; newList = permutationI(new ArrayList&lt;Character&gt;(indexes), i);
    addWord(charListToString(newList)); // Call our method to add the word to the result list
}