Constructing a 4×4 grid of words
I'm not sure if there's a faster way of doing it. However, your current code can be improved.
Enhanced for loop
Your loop are written using the traditional index:
String first;
for (int i = 0; i &lt; arr.size(); i++) {
    first = arr.get(i);
    // ...

When you don't need the index, it is better to use the enhanced for loop. This has the advantage that it makes the code more compact and easier to read:
for (String first : arr) {
     // ...

You are also calling multiple times arr.get(j) with the index instead of storing the result in a local variable. Using the enhanced for loop solves that directly.
String comparisons
Right now, you are comparing each String together with
if(first.substring(1,2).equals(arr.get(j).substring(0,1)) &amp;&amp;
    (!first.equals(arr.get(j)))){

There are a couple of comments here:

This is very hard to read: it is unclear what the code is doing ;
This is split in two lines and has a lot of parentheses which doesn't help
Each line is &quot;compact&quot; so it's hard to see what is actually happening.

To rewrite that, we should remember that what we're trying to do here: test whether the 2nd character of the 1st string is the same as the 1st character of the 2nd string. So, instead of using substring, let's use charAt which directly returns the character at the given index. The 2nd character of the first String is first.charAt(1); the 1st charcter of the second String is second.charAt(0). As such, we could have:
if (!first.equals(second) &amp;&amp; first.charAt(1) == second.charAt(0)) {
    // ...
}

Note the added spaces before the curly braces, between the operators and after the if statement, it also contributes to clarity.
Bizarre default condition
When the word currently considered is not a property fit, you are dping
else {
    second = &quot;    &quot;;
}

if (!second.trim().isEmpty()) {
    // ...
}

You are explicitely setting the String to whitespaces, only to trim it afterwards. This is a bit awkward.
What you want to do here is to continue when you reach an unwanted word. So you could have instead:
for (String first : arr) {
    for (String second : arr) {
        if (second.equals(first) || second.charAt(0) != first.charAt(1)) {
            continue;
        }
        for (String third : arr) {
            if (third.equals(first) || third.equals(second) || 
                first.charAt(2) != third.charAt(0) || second.charAt(2) != third.charAt(1)) {
                continue;
            }
            for (String fourth : arr) {
                if (fourth.equals(first) || fourth.equals(second) || fourth.equals(third) ||
                    first.charAt(3) != fourth.charAt(0) || second.charAt(3) != fourth.charAt(1) || third.charAt(3) != fourth.charAt(2)) {
                    continue;
                }

but now we're back to a mess: this is hard to read. However, it gives us insight into how can we do it better.
What we want is the following: we have a list of already found words (first and second for example); with that, we want to continue when the third is incorrect. What makes it incorrect is:

either it is equal to one of the previous found word
its characters do not match with the previously found words

So we can make a method of that!
Factoring common logic
private static boolean isIncorrect(String word, String... others) {
    boolean alreadyFound = Arrays.stream(others).anyMatch(word::equals);
    boolean notMatchedChars = 
        IntStream.range(0, others.length)
                 .anyMatch(i -&gt; word.charAt(i) != others[i].charAt(others.length));
    return alreadyFound || notMatchedChars;
}

This method is split in two (and uses Java 8 idioms but the logic would be the same without it). It takes as parameter a word to test and a vararg of the currently found words.

The first test checks whether any of the currently found words others are equal to the tested word.
The second test checks whether the characters are correct. If we have 3 currently found words then

the 1st character of the word must be equal to the 3rd character of the first word;
the 2nd character of the word must be equal to the 3rd character of the second word;
the 3rd character of the word must be equal to the 3rd character of the third word;



With that method, we can refactor our code to
void makeWord(List&lt;String&gt; arr) {
    for (String first : arr) {
        for (String second : arr) {
            if (isIncorrect(second, first)) {
                continue;
            }
            for (String third : arr) {
                if (isIncorrect(third, first, second)) {
                    continue;
                }
                for (String fourth : arr) {
                    if (isIncorrect(fourth, first, second, third)) {
                        continue;
                    }
                    System.out.println(first);
                    System.out.println(second);
                    System.out.println(third);
                    System.out.println(fourth);
                    System.out.println(&quot; &quot;);
                }
            }
        }
    }
}

which is very clean, although surely O(n4).