É só uma decisão de projeto.
O Windows deixa que os processos gerenciem os buffers de saída. Por isso ele não pode eliminar o subprocesso invocado até que esse buffer tenha sido completamente lido ou que o processo que originou o subprocesso seja fechado.
Normalmente o SO gerencia automaticamente isso com os pipes, mas no seu caso, você pegou o controle do pipe para si.
Se isso é bom ou ruim? Bom, já não entendo tanto de SO assim para saber se essa decisão é mais ou menos acertada…
Mas, em ambos os casos, o waitFor funciona. O objetivo dele é esperar que o processo seja morto. Só que a decisão de quando isso ocorre é deixada para o SO (mais uma das coisas não tão multi-plataforma assim do Java). Em todo caso, acho que a solução da thread separada não só é mais interativa, como funciona em todos os sistemas operacionais que eu já testei (Windows, Linux, Mac).