Java mergesort with generics
The first thing I would do is split up the while loop into 3 parts:
- handling both not empty
- add all remaining from left
- add all remaining from right

No wait, the first thing I did is paste the code in IntelliJ and have it autoformat to comply with the java coding conventions.
Since it's just some minor points like spacing I'm not going to list them here, overall your code looks decent already.

I also renamed a_iter and b_iter to leftIndex and rightIndex. Both because a variable shouldn't have an _ in it's name and because it better conveys what the variable is. Same for renaming a and b to leftElement and rightElement.

Now back to splitting up the while loop. I changed the || in the while condition to an &amp;&amp;, removed the "when xxx exhausted" parts and added the 2 new while loops after. This is the result:

int leftIndex = 0;
int rightIndex = 0;
while (leftIndex &lt; left.size() &amp;&amp; rightIndex &lt; right.size()) {
    T leftElement = left.get(leftIndex);
    T rightElement = right.get(rightIndex);
    if (leftElement.compareTo(rightElement) &lt; 0) {
        combined.add(leftElement);
        leftIndex++;
    } else {
        combined.add(rightElement);
        rightIndex++;
    }
}

// At least one of the sub lists is empty at this point.
// Just add all remaining elements from the other sub list.
while(leftIndex &lt; left.size()){
    combined.add(left.get(leftIndex++));
}
while(rightIndex &lt; right.size()){
    combined.add(right.get(rightIndex++));
}


Or if you want, replace the last while loops with an addAll

combined.addAll(left.subList(leftIndex, left.size()));
combined.addAll(right.subList(rightIndex, right.size()));




The biggest problem with this implementation is that it creates a lot of temporary lists. Taking a quick glance at how the built in list sort in java is implemented shows that they turn it into an array first, sort the array and then update the given list:

 public static &lt;T extends Comparable&lt;? super T&gt;&gt; void sort(List&lt;T&gt; list) {
     Object[] a = list.toArray();
     Arrays.sort(a);
     ListIterator&lt;T&gt; i = list.listIterator();
     for (int j=0; j&lt;a.length; j++) {
         i.next();
         i.set((T)a[j]);
     }
 }


Note that this doesn't return the list. It actually sorts the list you pass into it.

If you're looking for more improvements to the merge algorithm itself you could look up how it's implemented in java. (Although recently it's changed into a Tim sort which is a combination of merge sort and insertion sort).



As a final note: if your intention was to actually use your code in a project other than studying how merge sort is implemented or practicing your java skills I would advise against it. Just use the built-in functions if available.