Boggle solver in Java
According to the rules, you can only use each tile once per word.  You haven't attempted to keep track of tile usage.

Consider storing your dictionary using a trie, such as the implementation in Apache Commons.  It should provide an efficient .prefixMap(), which is like your dictionary.subSet().

You defined graph, but you never use it.

I think that an object-oriented interface would feel natural.  Create a new instance of Boggle by passing the char[][] matrix to the constructor.

Method names should be verbs, and shouldn't be redundant with the class name.  Therefore, .boggleSolver() should just be .solve().

The purpose of the loop…

for (int i1 = Math.max(0, i - 1); i1 &lt; Math.min(m.length, i + 2); i1++) {
    for (int j1 = Math.max(0, j - 1); j1 &lt; Math.min(m[0].length, j + 2); j1++) {
        if (i1 != i || j1 != j) {
            // loop body
        }
    }
}


… is to iterate through all the neighbours of tile (i, j).  A comment to that effect would be appreciated.  Also,  I would invert the if-condition to avoid a level of nesting:

// Iterate through the neighbours of tile (i, j)
for (int i1 = Math.max(0, i - 1); i1 &lt; Math.min(m.length, i + 2); i1++) {
    for (int j1 = Math.max(0, j - 1); j1 &lt; Math.min(m[0].length, j + 2); j1++) {
        // Skip the tile (i, j) itself
        if (i1 == i &amp;&amp; j1 == j) continue;

        String word = prefix+ m[i1][j1];
        if (!dictionary.subSet(word, word + Character.MAX_VALUE).isEmpty()) {
            if (dictionary.contains(word)) {
                validWords.add(word);
            }
            solve(m, i1, j1, word, validWords);
        }
}


Note that the dictionary.contains(word) check can be moved inside the !dictionary.subSet(...).isEmpty() check.