Antes de tudo, observe que eu sou C ++ e Python, não Java, portanto, parte disso pode não se aplicar tão completamente. Corrija-me se eu fizer algumas suposições incorretas sobre como as classes funcionam em Java.
As classes são úteis principalmente quando são instanciadas. Uma classe da qual nenhuma instância é criada é realmente apenas um espaço de nomes glorificado. Se você usar todas as suas classes dessa maneira, os benefícios de mover coisas de namespace para namespace podem parecer insignificantes - no máximo, você ganhará com alguns dados privados em cada uma delas e, assim, encapsulará um pouco as coisas.
No entanto, não é aí que as aulas brilham. Considere a Stringclasse: você pode ter todos os mesmos recursos usando charmatrizes e algumas funções estáticas. Nesse ponto, as funções oferecem um pouco de segurança extra e açúcar sintático. Você pode escrever em string.length()vez de length(char_array); isso não é grande coisa, mas muitas pessoas ainda gostam. Além disso, você sabe que se alguém lhe deu um String, ele foi criado com o Stringconstrutor e deve funcionar com a lengthfunção - se a versão do array não puder lidar com algum caractere, não haverá como impedir que você o coloque lá .
Ainda não é isso, no entanto. O ponto principal é que as classes agrupam dados e funções que operam nele e abstraem os dois. Quando você tem um método, void f(Builder b)sabe que receberá um Buildere pode esperar que ele suporte certo comportamento. No entanto, você não sabe nada sobre os dados ou as funções que estão sendo executadas - na verdade, as definições para ambos ainda não podem ser gravadas enquanto você escreve e compila f.
O primeiro ponto a entender é que as classes facilitam a transmissão de dados, garantindo que não sejam quebrados. O segundo ponto é que tanto os dados quanto a função (implementações) de um objeto têm algo sobre o objeto, não algo que você pode apenas dizer do seu tipo.