Aprenda Comigo: Java —Parte 3

Olá, mundão velho sem porteira

Cléber Zavadniak
clebertech
10 min readApr 22, 2017

--

Abrir uma IDE para escrever o “olá, mundo”. Okay…

Depois de dar uma olhada na lataria e fazer uma inspeção visual no motor, é natural que se dê a partida e siga-se com umas aceleradas quando se está avaliando um carro. Faremos a mesma coisa com o Java, hoje.

Instalação

O Java já vem instalado na maioria das distribuições Linux, embora haja um problema evidente de versão. Não no número da versão, mas o “fabricante” da mesma. Existe o “Open JDK”, por exemplo, e o “Oracle JDK”. Para quem declara imposto de renda e usa Linux, sabe que isso gera uma dorzinha de cabeça anual, já que os funcionários públicos da Receita não “homologam” o “Open JDK”, o que nos obriga a instalar a mesma versão do Java, mas de outro “fabricante” (a Oracle).

Vai entender…

Mas há um aspecto interessante, ainda, que é a existência do Java JDK e Java JRE. Basicamente, o JRE (Java Runtime Environment) é a máquina virtual/interpretador (JVM) e as bibliotecas relacionadas, tudo o que, a princípio, é necessário para rodar um programa escrito em Java.

O JDK é o Java Development Kit, que já contém o JRE e inclui ferramentas para desenvolvimento, como o compilador de Java ( javac ).

Olá, mundão

Quero desenvolver um pequeno programa que funciona assim: se eu executá-lo sem argumento algum, ele imprime no terminal “Olá, mundo”. Mas se eu passar parâmetros, eles devem ser unidos ( string join) separados por um espaço em branco (``) e devem ser impressos logo após “Olá, “.

Em Python

Para essa série, usarei Python como nossa “meta-linguagem”:

Muito simples: para imprimir o “Olá, <alguma-coisa>` nós temos uma função que recebe o <alguma-coisa> como parâmetro. Abaixo dela, verificamos se o arquivo está sendo chamado direto da linha de comando, caso em que __name__ é igual a __main__ , já que não queremos que aconteça nenhum I/O caso este mesmo aquivo seja chamado como um módulo.

Yay!

O script poderia ser ainda mais simples caso ignorássemos o __name__ e outros detalhes, mas achei interessante já fazer do jeito certo para vermos como, mesmo assim, uma tarefa simples acaba refletindo em código também simples. (Ah, e isso fará todo sentido quando escrevermos testes. Confie em mim.)

Em Java: primeira versão

Aff, como foi [desnecessariamete] difícil! Para fazer isso eu precisei pesquisar por:

  • java hello world
  • java string concatenation
  • java string join
  • java iterate through list
  • java Iterator start at another position

E, apesar de tudo parecer bem correcto…

CARAMBA! Fazia algum tempo que eu não ficava preso nessa fase bizarra de “escreve-compila-dápau, escreve-compila-dápau…”.

Sem iteradores

Acabei descobrindo que não precisava de um Iterator para iterar sobre os args . Eu inferi isso lendo algum código de exemplo no StackOverflow. Para mim isso acabou sendo um tanto confuso: preciso lembrar que Java é uma linguagem “tipo baixo nível” e que tem muito mais similaridade com C/C++ do que com linguagens de altíssimo nível como Perl, Python ou Ruby.

A versão quase sem erros ficou assim:

E os erros ficaram assim:

Estático versus não-estático

Também esqueci desses detalhes de alocação de memória. Enquanto o método main é estático, meu hello não o era.

Nova versão:

O compilador também me obrigou a colocar aquele return 0 no final, já que eu havia declarado meu método main, como seria correto, como int .

Ops! Não pode ser int! E magic!

Primeiro: quando compilei meu hello.java o “javac” me gerou um arquivo HelloWorldApp.class . Já não gostei disso.

Segundo: como diabos se executa o programa? Com mágica! Embora você tenha escrito teu código em hello.java e embora o compilador tenha gerado um arquivo HelloWorldApp.class , você executa o teu programa chamando um tal de HelloWorldApp , que sequer é um nome de arquivo no teu sistema de arquivos local!

Terceiro: apesar de que todo programa deve retornar um status de execução, que é um número inteiro, o Java não me deixa definir um método main que não seja do tipo void :

Okay…

// TODO: descobrir como retornar o status de execução do programa para o sistema operacional.

Versão final. Ou é?

Tudo okay, agora, certo? Então vamos testar!

Ops! What happened? Vamos tentar de novo:

Outra descoberta incrível: ao contrário do resto do mundo, parece que Java não coloca o nome do executável em args[0] . Legal, hein?

// TODO: descobrir como pegar o nome do executável no Java.

Nova versão:

Agora sim! Ou não?

Não! Como eu disse no começo, se eu não passar nenhum argumento, deve-se imprimir “Olá, mundo”. Mas…

Adicionando uns “ifs”

Parece correcto, não? Tem até um “early return” razoavelmente elegante, ali.

Mas, não, o compilador não gosta:

Não pode ter return em método void

Solução? Um “maravilhoso” else :

Argh! Mas agora, pelo menos, funciona:

Principais dificuldades

Versões e onde encontrar ajuda

A internet está repleta de sites e tutoriais de Java, mas ao buscar por ajuda, fiquei caindo constantemente em 3 categorias:

1- StackOverflow, que é um universo à parte.

2- Sites da época que se buscava coisas via Cadê.

3- O site oficial.

O problema do StackOverflow é que há perguntas lá datadas de “circa 1997” e certas coisas, que eram corretas antigamente, hoje já não o são. Achei bem complicado achar respostas específicas para o Java 8.

Nos sites antigos é difícil conseguir algo além de exemplos muito básicos e mesmo estes não me parecem muito confiáveis.

E o site oficial, por sua vez, é muito feinho (é extremamente desagradável navegar por ele) e achei o conteúdo ou demasiado verborrágico e cheio de rodeios ou simplesmente incompleto. Por exemplo: eu comecei a tentar criar um Iterator para iterar sobre os argumentos de linha de comando (um erro, eu sei) e a documentação oficial até dá exemplos de uso, mas tive que “chutar” um import java.utils.Iterator que não era citado em lugar algum (ou será que só quem usar openjdk precisa disso?). O mesmo aconteceu com a StringJoiner

O quanto isso é um problema intrínseco do Java? Não sei. Só sei que algo não cheira bem. Deixarei para analisar isso nos próximos capítulos dessa série.

“Orientação a Objetos” e mágica

Por que diabos eu preciso criar uma classe? A dita cuja sequer será instanciada! E ela só tem dois métodos — que são estáticos!

O grande problema do Java é essa tentativa de ser “object oriented only” e, de certa forma, foi quem popularizou as “object oriented languages”. Mas é preciso entender que Orientação a Objetos não é um paradigma de programação, mas simplesmente uma forma de modelar problemas. Não existe tal coisa como uma “linguagem orientada a objetos”. Java é simplesmente mais uma linguagem procedural, como C, C++ ou Python. É procedural porque você escreve como o computador deve fazer as coisas, ao contrário, por exemplo, de dizer simplesmente o que ele deve fazer, como seria numa linguagem funcional ou descrever um universo de fatos, como em programação lógica.

É preciso ter muita cautela com essas questões de “paradigma de programação”. C, por exemplo, é uma linguagem procedural, mas permite que você programe com uma mentalidade funcional ou mesmo que programe orientado a objetos. É complicado definir limites estritos com relação a qual paradigma determinada linguagem suporta — vide as intermináveis discussões que cercam o assunto.

Todavia, me parece um erro óbvio tentar considerar Orientação a Objetos como um paradigma de programação per si e ainda por cima criar uma linguagem que tente tão escancaradamente dar “suporte completo” a esse “paradigma”. As linguagens de programação “suportam” Orientação a Objetos, não “são” orientadas a objetos como a linguagem Java tenta ou diz ser.

E essa tentativa de prender o programador em uma jaula-de-OO nos leva ao próximo ponto, que é:

Ficar agradando o compilador

Eu passei alguns anos da minha vida programando em linguagem C. E alguns anos lidando com C++, também. Eu sei bem o que é ficar tentando compilar um programa, ficar depurando erros de compilação, alterando, tentando, alterando, tentando até finalmente dar certo (e descobrir um bug em tempo de execução). Isso é até okay, mas minha pergunta é: pra quê?

Bom, eu sei bem o que acontece quando um programa em C é compilado. É uma necessidade muito básica declarar-se tipos em todo lugar, já que o compilador há de traduzir tudo para linguagem de máquina e fazer uma comparação, digamos, entre 1 (int) e 1.0 (float) requer, de fato, uma coerção de tipos, já que, no fim das contas, a comparação é feita no nível mais baixo possível, a Unidade Lógica Aritmética da CPU. Há circuitos elétricos envolvidos, sinais que devem estar altos ou baixos na hora certa para que 1seja igual a 1 ou 1.0 seja igual a 1.0 , do jeito que deve ser.

Mas, se estamos compilando para execução em uma máquina virtual, qual é a necessidade disso? Pense além da simulação das instruções de uma CPU, pense além dos circuitos elétricos: por que um desenvolvedor que quer escrever um “hello, world” precisa declarar sua função como void ? Por que ele precisa lembrar que main precisa ser static, public e void ?

Acabei passando mais tempo tentando passar pelo compilador do que gastei tentando resolver meu problema!

Para entender melhor o que eu digo, façamos uma comparação: vou pintar de verde o que é solução de problema, vermelho o que é pura burocracia, azul o que é convenção e amarelo o que é necessidade aceitável da linguagem em ambos os programas: Python e Java. Vejamos:

Python
Java

Em Python eu não preciso escrever nada que seja meramente agrado a compilador/interpretador. E repare, também, que eu consigo resolver meu problema com muito menos linhas de código. E o código gerado é muito mais legível.

Na verdade, eu consigo resolver meu problema com apenas duas linhas de código Python, até:

Enquanto com Java eu preciso me preocupar com trivialidades, como o índice do for , o tipo da variável string_joiner , os tipos de retorno dos métodos, se eles são estáticos ou não e suas permissões de acesso. E isso não tem nada a ver com a resolução do problema.

Ou seja: Java cobra impostos para poder te ajudar a resolver os teus problemas.

Resumo

Temos aqui nosso “lindo” programa “Olá, mundo” escrito em Java. Não tecerei maiores considerações, ainda, porque ainda acho cedo para tal.

No próximo capítulo escreveremos testes para este mesmo programa. Fique ligado!

--

--