Published on

A filosofia por trás da linguagem Java

Authors

Introdução

Embora computadores e linguagens de programação possam ser vistos como construtos matemáticos sendo, nesse sentido, passíveis de análise objetiva, na prática, mais especialmente em se tratando de desenvolvimento e manutenção de software, fatores humanos acabam por tomar relevância. Uma das influências mais curiosas sobre o universo da computação, é a psicologia de grupo. Restringindo aqui este fenômeno apenas a linguagens de programação é possível notar que aqueles que se identificam como programadores "x", onde x é uma linguagem por vezes demonstram:

  1. Homogeneidade de exogrupo
  2. Dogmatismo
  3. Favoritismo intragrupal

Homogeneidade de exogrupo consiste em caracterizar indíviduos fora do grupo como sendo mais parecidos do que realmente são, por exemplo, reduzir todas as linguagens que não são aquela que meu grupo usa com iguais e inferiores por, por exemplo não terem controle de funções de baixo nível, ou pelo contrário, por terem. Pela sintaxe ser simples demais, ou, de forma complementar, muito complexa.

Dogmatismo, por sua vez, consiste na crença de que há determinadas proposições sobre a linguagem que devem ser aceitas sem questionamentos, isto é, a forma como uma determinada linguagem desempenha alguma função, é a única forma correta e isso está além de questionamento.

Por fim, favoritismo intragrupal consiste na tendência de parcialidade em favor dos membros do próprio grupo. O que também pode ser verificado na (má) prática de programação.

É necessário compreender que linguagens de programação, são ferramentas, meios para um fim, e que diferentes linguagens, por vezes, buscam suprir diferentes necessidades, fazendo com que a questão "qual a melhor linguagem de programação?" não passe de ruído, um questionamento sem sentido, fundado em erros de raciocínio bem documentados em psicologia de grupo.

É o caso pois, que para se tirar o maior proveito possível de uma ferramenta, devemos compreender a filosofia por trás do seu design. E é com este intuito que eu inauguro a série "a filosofia por trás". Na edição de hoje, buscarei elucidar quais princípios e preocupações guiaram o desenvolvimento da linguagem de programação Java.

Write once, run anywhere

Java foi criada em 1991, sob o nome de Oak e renomeada para Java em 1995. Sua motivação fundamental estava conectada a necessidade de implementar software para sistemas embarcados em produtos como torradeiras, microondas e controles remotos. As alternativas da época para esta finalidade consistiam basicamente em C e C++ e, embora essas linguagens desempenhem essa função com excelência, um compilador C/C++ específico deveria ser implementado para cada CPU. Logo a proposta do Java era a portabilidade. A possibilidade de fazer um único código que pudesse ser portado para uma infinidade de arquiteturas.

Este objetivo, embora certamente justificado, teve sua importância inflacionada pela popularização da internet. Dada a natureza distribuída da web, assim como sua constituição por uma diversidade de computadores rodando uma variedade de sistemas operacionais diferentes, portabilidade, algo anteriormente desejável, mas não substancial, tornou-se uma questão fundamental, levando a uma explosão de popularidade da linguagem, a qual passou a ser utilizada tanto no lado do cliente, na época na forma de applets, os quais foram descontinuados na versão 11 da linguagem, quanto do servidor, através de serverlets.

Para entender entretanto essa popularização, precisamos compreender como exatamente a linguagem solucionou o problema da portabilidade e quais vantagens e desvantagens fazem parte desta solução.

Portabilidade, Segurança e o Bytecode

A ideia de que uma aplicação teria exatamente um código para ser executada em diferentes computadores é de extremo interesse prático, economizando muito tempo de desenvolvimento. Entretanto, sabemos que durante o processo de compilação, um compilador transforma o código de alto nível escrito pelo programador em instruções de máquina, as quais devem ser específicas para a plataforma envolvida. O truque do Java, portanto, é que seu compilador, Javac, não tem como saída código de máquina, mas algo conhecido como bytecode .

O bytecode consiste em um conjunto de instruções altamente otimizado feito para ser executado pela Java Virtual Machine (JVM), a qual faz parte do Java Runtime Environment (JRE). Ou seja, uma vez compilado em bytecodes o código Java é interpretado pela JVM.

Esta abordagem faz com que não seja necessário implementar um novo compilador para cada plataforma, mas tão-somente um ambiente de execução (JRE). E, ainda que os detalhes de JRE de cada plataforma sejam variáveis, todos eles intrepretarão o mesmo bytecode, fazendo com que apenas uma versão do programa precise existir.

Curiosamente a utilização da máquina virtual JVM também auxilia na segurança da linguagem. Como é a JVM que está no controle, ela gera um ambiente de execução restrito chamado de sandbox, contendo o programa e removendo acesso irrestrito à máquina real.

É visível como programas que pudessem ser executados sem grandes riscos e em qualquer tipo de computador popularizaram Java em seus primórdios.

Velocidade

Embora Java seja uma linguagem compilada e interpretada, como o bytecode foi altamente otimizado a velocidade da JVM é muito superior a outras linguagens interpretadas como Python e Pearl. Além disso há duas técnicas que podem aumentar drasticamente o desempenho de Java:

  1. HotSpot JVM
  2. Ahead-of-time compiler

A HotSpot JVM contém um compilador just-in-time, conhecido em português como compilador dinâmico, para bytecode. Esta abordagem faz com que porções de bytecode sejam compiladas em código de máquina em tempo real de acordo com a demanda. Isto é, o compilador JIT compila código a medida que ele é necessário durante a execução, ignjorando sequẽncias que não receberão benefício por serem compiladas. É importante notar que a compilação dinâmica ainda mantém o código portável e seguro, já que ela ainda depende da JVM.

Nas versões subsequentes a JKD9, alguns ambientes de desenvolvimento Java suportam compiladores ahead-of-time, ou seja, a compilação de bytecode para instruções de máquina ocorre antes da execução. Essa é uma abordagem especializada.

Ambas abordagens podem otimizar em grande medida o tempo de execução de um código em Java.

Características Notáveis

CaracterísticaJustificativa
PortávelProgramas Java podem ser executados em qualquer ambiente desede que haja uma JRE
SeguraProvê meios seguros de criar aplicações web via JVM
Orientada a ObjetosÉ orirentada a objetos
RobustaEvita erros por ser fortemente tipada e fazer checagens em tempo de execução
DinâmicaProgramas Java têm uma quanitdade substancial de informações de tipo em tempo de execução, as quais são utilizadas para verificar e resolver acesso a objetos em tempo de execução
MultithreadedSuporta computação concorrente

Conclusão

Podemos perceber que, evitando uma visão maniqueísta de linguagens de programação, Java não aparece como a melhor nem a pior linguagem. Ela não é a mais rápida, mas essa jamais foi a filosofia por trás do seu design, devemos julgar uma ferramenta considerando a finalidade por trás de sua produção. Observando o contexto de criação do java somos capazes de perceber onde a linguagem trabalha com excelência, assim como quais são seus pontos fracos. Se as prioridades de um projeto são portabilidade e segurança, Java com certeza é uma boa linguagem para o trabalho. Se, por outro lado, desejamos outras características, como minimalidade, liberdade com funções de baixo nível ou simplicidade sintática, há alternativas mais adequadas. A mensagem a ser guardada, entretanto, é que uma ferramenta deve ser bem conhecida para decidir quando empregá-la e como bem empregá-la.


Referências:

  1. Schildt, Herbert. Java: A Beginner's Guide, Eighth Edition. McGraw Hill Education 2018.
  2. https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-9-82