Você está na página 1de 31

Análise Sistemática da Linguagem Groovy

Anna C. S. Medeiros, Leandro Figueiredo Alves, Luciano Medeiros, Rafael de Castro


linnamedeiros@gmail.com, leandrotschreck@gmail.com,
lucianomedeiros@hotmail.com, rafaelhenriquec@gmail.com

Departamento de Informática – Universidade Federal da Paraíba (UFPB)


João Pessoa – PB – Brasil

Abstract. This article aims to systematically analyze the Groovy scripting language,
designed to generate Java interpreted code in order to explain the features and
paradigms of the language and display some new concepts introduced by the same,
demonstrating these concepts with examples and comparing with its "mother
language" Java.

Resumo. Este artigo visa analisar sistematicamente a linguagem script Groovy,


desenvolvida para gerar código interpretado para Java, visando explanar as
funcionalidades e paradigmas da linguagem e mostrar alguns novos conceitos
introduzidos pela mesma, demonstrando esses conceitos com exemplos e
comparando com sua “linguagem mãe” Java.

1. INTRODUÇÃO
Ao contrário do Microsoft .Net, Java (linguagem e plataforma) não foi criada visando o uso de
várias linguagens para gerar código interpretado (bytecodes em Java, MSIL - Microsoft
Intermediate Language - em .Net). Com os anos, a comunidade Java criou suas próprias
ferramentas para compensar este fato, na forma de linguagens que geram bytecodes
compatíveis com os produzidos pelo compilador da linguagem Java.
Groovy é uma destas linguagens, talvez a mais conhecida. É um projeto de Software
Livre hospedado na Codehaus responsável por outros projetos como XStream, Pico/Nano
Container, AspectWerkz, ActiveMQ, JMock, Drools e tantos outros. A linguagem Groovy é
padronizada pela JSR 241.
O grande foco de Groovy é a produção de scripts, como os feitos em Bash ou Perl,
mas a linguagem é poderosa o suficiente para ir muito além. Alguns programas podem exigir
que rotinas sejam configuráveis e a maioria dos grandes sistemas empresariais, como ERPs e
outros sistemas vendidos como produtos, permite um alto nível de personalização por cliente.
Imagine um software de frente de caixa que precisa aceitar promoções definidas pelo time de
marketing várias vezes por ano.
Na maioria das vezes estas configurações são implementadas com algum nível de
parametrização em arquivos de configuração, mas quando existe uma mudança grande (como
uma promoção "compre dois produtos do lote ABC-001 e leve mais um") geralmente o
desenvolvedor precisa codificar esta em Java e fazer outro deploy da aplicação. Com
linguagens de script, isso pode ser alterado dinamicamente. Neste artigo, veremos suas
principais características.

2. HISTÓRICO
No dia 29 de agosto de 2003 James Strachan publicou em seu blog o primeiro artigo sobre
aquilo que viria a ser o Groovy. Ele deixava bem claro as suas intenções na época: “minha
idéia inicial é fazer uma pequena linguagem dinâmica, que seja compilada diretamente em
classes Java e que tenha toda a produtividade elegante encontrada em Ruby e Python, mas que
permita reusar, estender, implementar e testar código Java já existente”.
James procurava uma linguagem dinâmica para desenvolver em plataforma Java, e
em seu post ele deixava claro que as opções da época não eram interessantes. Ele não queria
apenas uma linguagem dinâmica, mas sim algo que pudesse ser integrado ao que ele já tinha
pronto em Java, algo que acelerasse seu desenvolvimento e que não o obrigasse a jogar tudo o
que tinha de código Java já pronto e testado (e em produção) no lixo. Enfim, ele queria algo
que não existia na época.
James então uniu-se a Bob McWhirter e juntos fundaram o projeto Groovy em 2003.
Logo, com um grupo de pessoas que compartilhavam da mesma idéia, iniciaram o
desenvolvimento da linguagem. Foi em 2004, com a fundação do GroovyOne e a entrada de
outros desenvolvedores que tudo decolou. Foi criada a Groovy Language Specification (GLS)
e o kit para testes de compatibilidade (o TCK), além do parser básico da linguagem. O
embrião do projeto estava pronto e a partir daí não teria mais como voltar atrás.
Groovy evoluiu desconhecido por algum tempo, e até dezembro de 2007 várias
versões foram lançadas sob o número 1.1.x. Em 7 de dezembro de 2007 a versão final da
família 1.1 foi lançada, e então nomeada Groovy 1.5 devido às diversas modificações
realizadas na mesma. Hoje a linguagem é uma especificação do JCP (JSR 241) e é
considerada a segunda linguagem oficial da plataforma.
Ao contrario do que alguns pensam, Groovy não é um concorrente do Java, mas uma
ferramenta de apoio e de produtividade.

3. SISTEMA DE TIPOS
Ao contrário de Java em que possuímos tipos primitivos e não primitivos, em Groovy tudo é
considerado objeto. Os tipos compostos são abstraídos com as operações avançadas de
Orientação a objeto, como herança, porque não existem tipos primitivos.
Tornar atividades comuns mais convenientes é uma das principais promessas do
Groovy. Consequentemente, Groovy torna até mesmo os mais simples tipo de dados em
objetos de primeira classe e implementa operadores como chamadas de métodos para fazer os
benefícios da orientação à objetos disponíveis.
A Conveniência ao programador é aumentada permitindo uma variedade de meios
para declarações literais de string, seja através das flexíveis declarações Gstring ou com a
sintax para situações onde escape extra é indesejável, como padrões de expressão regulares.
Gstrings contribuem para outro dos pilares centrais do Groovy: código conciso e
expressivo. Isto permite ao leitor uma clara visão do valor corrente da string, sem ter que
passar por reinos de concatenação de strings ou trocar de formatos de string e os valores lá
contidos.
A escolha entre tipagem estática ou dinâmica é também uma das chaves dos
benefícios do Groovy. A internet está cheia de discussões sobre qual a melhor tipagem. Em
outras palavras, não existem bons argumentos para nenhuma posição. Sistemas de tipos
estáticos promovem mais informação para otimização, checam melhor na hora da compilação,
e promovem melhor para suporte para IDE. Também revelam informações adicionais sobre o
significado de variáveis ou parâmetros de métodos, além de permitir sobrecarga de métodos.
Tipagem dinâmica, não somente é conveniente para o programador mais relaxado
que faz script do tipo ad-hoc, como também é confiável e economiza linhas de programação.
Groovy é uma linguagem mista, onde se pode obter os benefícios da tipagem estática ou os
benefícios da tipagem dinâmica.
Em se tratando de números, no que diz respeito à conversão de tipos e gerenciamento
com precisão, Groovy promove um uso intuitivo, até mesmo para não-programadores. Isto se
torna particularmente importante quando scripts Groovy são usados para configuração
inteligente de grandes sistemas onde usuários empresários provêem fórmulas.
Strings, expressões regulares e números, todos são beneficiados por vários métodos
que o GDK(Kit de Desenvolvimento Groovy) introduz em cima do JDK.
Os designers da linguagem Groovy estão bem cientes dos conceitos que estão
raramente longe das mentes de um programador
O trabalho foi desenvolvido baseado em uma visita feita a empresa em questão onde
foi feita uma entrevista com o dono da empresa Renato Silva Rodrigues, com perguntas
formuladas para abranger todo o conteúdo abordado na disciplina Administração de
Empresas, afim de construir o seguinte relatório a partir das respostas obtidas sobre o
funcionamento da empresa, podendo assim discuti-las de acordo com o assunto abordado em
sala de aula.

4. EXPRESSÕES
Uma expressão é uma construção que é avaliada e produz um valor.
Na linguagem Groovy temos os seguintes as seguintes formas fundamentais de
expressões:
 Literais;
 Construções;
 Chamadas de Funções;
 Expressões Condicionais;
 Acesso de Constante e de Variável.
A linguagem Groovy não possui expressões iterativas, mas possui, além das outras
formas fundamentais de expressões, expressões regulares.

4.1. Literais
O tipo mais simples de expressão. Denota um valor fixo de algum tipo.
Tem-se como exemplos de literais para a linguagem Groovy:
 125
 1.23
 “Hello”
 “““first line,
second line
and third line”””

4.2. Construções
É uma expressão que construe um valor compost a partir dos seus valores components. Em
Groovy tem-se construções tais como: List, Map, Ranges e Objetos.

4.2.1. List
É uma estrutura usada para armazenar uma coleção de itens de dados.
Definição de uma lista:

def numbers = [11, 12, 13, 14]


Acesso do elemento de índice 0 (11):
numbers [0]

4.2.2. Map
Coleção de referências de objetos desordenada.
Definição de um map com integers como chave e a lista de seus divisores:
def divisors = [4 : [2]. 6 : [3, 2]. 12 : [6, 4, 3, 2]]
Acessar um elemento do map com a chave 6 ([3, 2]):
divisors[6]

4.2.3. Ranges
Utilizado para especificar uma seqüência de valores. Exemplo:
„A‟..„D‟ //A, B, C e D

4.2.4. Objetos
Para a utilização de um objeto é necessário definir suas propriedades em uma classe. A
estrutura de uma classe em Groovy é a seguinte:

class Account{
//Atributos
def number
def balance
//Método
def credit(amount){
balance += amount
}
}

A instanciamento do objeto:

def acc = new Account(number : „ABC123‟. Balance : 1200)

4.3. Chamada de Funções


Uma chamada de função computa um resultado aplicando um método a um ou mais
argumentos. Exemplo de método:
def getAccountBalance(number){
def acc = this.findAccount(number)
return (acc == null) ? null : acc. Balance
}

Exemplo de chamada de função (objeto que possui o método: bk):

def balance = bk.getAccountBalance(„ABC123‟)


Um operador também denota uma função:
def number = 2 * 3

4.4. Expressões condicionais


Computa um valor que depende de uma condição. Estrutura em Groovy:

expr ? expr1 : expr2

Se expr é true então o valor de expr1 é o resultado, se é false o valor de expr2 é o


resultado.

4.5. Acesso de constante e de variável


Um acesso de constante é uma referência a uma constante e um acesso de variável é uma
referência a uma variável. Exemplo de constante e variável, respectivamente:

final String CONSTA = „a‟


String varA = „a‟

4.6. Expressões regulares


Uma expressão regular é um padrão usado para encontrar substrings em texto. Groovy suporta
expressões regulares nativamente utilizando a expressão ~“regex”, onde o texto dentro das
aspas representa a expressão regular.
Exemplo:

Def regex = ~„cheese‟


Quando o operador do Groovy =~ aparece como um predicado em comandos if e
while, o String da esquerda é comparado com a expressão regular da direita. Os seguintes
exemplos retornam true:

„cheesecake‟ =~ „cheese‟
„cheesecake‟ =~ regex

O operador ==~ requer uma equivalência perfeita.


Em uma expressão, dois caracteres posicionais são usados para denotar o começo e o
final de uma linha: ^ e $:

def rhyme = „Humpty Dumpty Sat on a wall‟


rhyme =~ „^Humpty‟
rhyme =~ „wall$‟

Expressões regulares podem incluir também quantificadores:


 + representa uma ou mais vezes, aplicado ao elemento precedente;
 * representa zero ou mais ocorrências;
 ? denota zero ou uma vez;
 { } é utilizado para definir um específico número de ocorrências do caractere
precedente.
Exemplos dos quantificadores:

„aaaaab‟ =~ „a*b‟
„b‟ =~ „a*b‟
„aaaaab‟ =~ „a{5}b‟
O símbolo . pode representar qualquer caractere. É possível definir um grupo de
caracteres possíveis com o uso de [ ], criando assim uma classe de caracteres. Seqüências de
letras ou números podem ser representadas por -, como: [a-z].
O complemento de uma classe de caracteres é denotado por um ^ dentro dos
colchetes: [^a-z].

5. COMANDOS
Um comando é uma construção do programa que será executada para atualizar variáveis.
A linguagem Groovy possui os seguintes comandos:
 Atribuições;
 Chamadas de Método;
 Comandos Sequenciais;
 Comandos Condicionais;
 Comandos Iterativos.
Groovy proporciona uma facilidade na iteração de coleções, o método each, que será
mostrado mais a frente.

5.1. Atribuições
Uma variável é atualizada para armazenar um valor. Esse comando tem a forma: V = E, onde
V é um acesso da variável e E é uma expressão que retorna uma valor para ser armazenado.
Exemplo:

def count = 0

5.2. Chamadas de métodos


É um comando que alcança seu efeito aplicando um método para alguns argumentos. Classe
usada para o próximo exemplo:

Class Account{
def balance
def credit(amount){
balance += amount
}
}

Exemplo de chamada de método para a classe Account:

acc.credit(50) //Atualiza a variável balance somando-a ao valor do parâmetro

5.3. Comandos sequenciais


Um comando seqüencial especifica dois ou mais programas serão executados em seqüência.
Um comando seqüencial pode ser escrito da seguinte forma: C1; C2 (C1 executa primeiro que
C2).
Exemplo em Groovy:

print „Hello‟; print „!!!‟

5.4. Comandos condicionais


Possui dois ou mais subcomandos, dos quais exatamente um é escolhido para ser executado.

5.4.1. Comando if
Forma geral do comando if:

if(condição){
comando1a
...
} else{
comando2a
...
}
Se a condição for verdadeira é executado o corpo do bloco if, se for falsa é executado
o bloco else.

5.4.2. Comando switch


Sintaxe:
Switch(expressão){
case expressão 1:
comando 1a
...
...
case expressão N:
comando Na
...
default:
comando Da
...
}

A expressão entre parênteses é avaliada, e seu resultado é comparado com as


expressões dos cases. Se alguma expressão dos cases for equivalente a expressão, todos os
comandos do case com a expressão equivalente até o final são executados. Se não houver
nenhum equivalente então se executa os comandos do default.
Para executar só um case, pode se usar o comando break, colocando-o no final do
bloco de comandos do case, que quando o comando break é executado sai-se do switch.

5.5. Comandos iterativos


Um comando iterativo tem um subcomando que é executado repetidamente.
5.5.1. Comando while
Sintaxe do comando while:

while(condição){
comando 1
comando 2
...
}

Enquanto a condição for verdadeira os comandos no corpo do while serão


executados.

5.5.2. Comando for


Em Groovy o comando for pode ser usado com um Range, uma coleção ou um String.
Sintaxes:

for(variable in range){
...
}
for(variable in collection){
...
}

for(variable in string){
...
}

Exemplos:
//Range
def LIMIT = 10
for(count in 1..LIMIT)
println “count: ${count}”
//List
for(count in [11, 12, 13, 14])
println “count: ${count}”
//Map
def staff = [„Ken‟:21, „John‟:25, „Sally‟:22] //Nome e idade
def totalAge = o
for(staffEntry in staff)
totalAge += staffEntry.value
//String
def name= „Kenneth‟
def listOfCharacters = [ ]
for(letter in name)
listOfCharacter<<letter

5.5.3. Método each


Em Java temos o seguinte modo de iterar uma coleção:

for (Iterator collection.iterator(); iterator.hasNext(); ){


MyClass obj = (MyClass) iterator.next();
// do something with obj
}

Groovy proporciona um modo mais simples de se fazer isso:

collection.each { /* do something with it */}


6. FORMAS DE DECLARAÇÃO E BLOCOS
Assim como em Java, as estruturas de bloco são definidas entre „{‟ e „}‟. Assim como Java,
Groovy usa os escopos estáticos, suportando também blocos aninhados. Essas estruturas
podem ser classe, interface, inicializadores de objeto ou estáticos ou corpos de métodos,
podem aparecer com as palavras chave Groovy como if, else, synchronized, for, while, switch,
try, catch e finally. Todas as ocorrências são closures.

6.1. Closures
Um closure seria um pedaço de código dobrado como um objeto. Ele age como um método
que pode conter parâmetros e pode retornar um valor. É um objeto normal em que você pode
estar rodando um código Groovy, então não há nada particularmente estranho que poderia
estar fazendo com um objeto closure. É apenas um objeto. [1] Eles podem ser armazenados
em variáveis, podem ser passados adiante e pode-se chamar métodos neles. Sendo objetos,
closures podem também ser retornados de um método.
O mecanismo de escopo do Groovy é também significativamente mais flexível e
poderoso, enquanto remove o excesso de código que as classes de Java introduzem. Veja o
exemplo de uma classe Java, com os elementos importantes em negrito:
// Java
interface ResourceUser {
public void use (Resource resource)
}
resourceHandler.handle(new ResourceUser() {
public void use (Resource resource){
resource.doSomething()
}
O equivalente Groovy deste código revela todas as informações necessárias sem
qualquer desperdício:
resourceHandler.handle { resource -> resource.doSomething() }
6.2. Usando closures
Chamando um closure: Suponha que nós tenhamos uma referencia x apontando para um
closure; nós podemos chamá-la com um x.call() ou simplesmente x(). Quaisquer argumentos
para a chamada do closure vão sempre entre parênteses:

def adder = { x, y -> return x+y }


assert adder(4, 3) == 7
assert adder.call(2, 6) == 8

A classe groovy.lang.Closure é uma classe ordinária, apesar de ser uma com


poder extraordinário e suporte extra de linguagem. Ela tem vários métodos disponíveis além
de call. A seguir são apresentados os mais importantes.

6.2.1. Reagindo na Contagem de Parâmetro


Um exemplo de quão útil é reagir na contagem de parâmetro de um closure é seu método each
do map. Ele passa tanto um objeto Map.Entry ou chave e valor separados no closure dado,
dependendo se o closure leva um ou dois argumentos. Você pode conseguir a informação
sobre a contagem esperada de parâmetros (e tipos, se declarados) chamando-se o método de
closure getParameterTypes:

def caller (Closure closure) {


closure.getParameterTypes().size()
}
assert caller { one -> } == 1
assert caller { one, two -> } == 2

Isso permite a luxúria de suportar closures com diferentes estilos de parâmetro,


adaptados às necessidades do caller.
6.2.2. Como Fazer Curry Favor com um Closure
Currying é uma técnica inventada por Moses Schönfinkel e Gottlob Frege, e nomeada pelo
lógico Haskell Brooks Curry (1900..1982), um pioneiro em programação funcional. A idéia
básica é tomar uma função com múltiplos parâmetros e transformá-la em uma função com
menos parâmetros, fixando alguns dos valores. Um exemplo clássico é escolher algum valor
arbitrário n e transformar uma função que some dois parâmetros em uma função que leva um
único parâmetro e adicionar n a ele.
No Groovy, o método Closure`s curry retorna um clone do closure atual, tendo como
limite um ou mais parâmetros para um valor dado. Parâmetros são limitados pelos argumentos
do curry da esquerda para a direita. O exemplo sequinte mostra uma implementação:

def adder = { x, y -> return x+y }


def addOne = adder.curry (1)
assert addOne (5) == 6

Desta maneira reutilizamos o mesmo closure agora para soma geral. Nós chamamos
o método curry nele para criar um novo closure, que age como um simples adicionador, mas
com o valor do primeiro parâmetro sempre fixado em 1. Finalmente, checa-se o resultado.

6.2.3. Classificação pelo Método isCase


Closures implementam o método isCase para fazer os closures funcionarem como
classificadores em grep e switch. Neste caso, o argumento respectivo é passado no closure, e
ao chamar o closure precisa-se avaliar a um valor Boolean Groovy. Como se pode ver em:

assert [1, 3, 3].grep{ it<3 } == [1, 2]


switch (10) {
case { it%2 == 1 } : assert false
}
Isso nos permite classificar por lógica arbitrária. Novamente, isso é possível apenas
porque closures são objetos.

6.2.4. Métodos Remanescentes


Em favor da completude, é preciso dizer que closures suportam o método clone no sentido
usual Java.
O método asWritable retorna um clone do closure atual que tem um método
adicional writeTo(Writer) para escrever o resultado de uma chamada de closure diretamente
ao Writer dado.

6.2.5. Escopo
O que está disponível dentro de um closure, como:
 Variáveis locais;
 O que this se refere;
 Campos e métodos acessíveis;
 Todo o closure é limitado pelo bloco, definido entre „{„ e „}‟.

6.2.6. Estruturas de Controle


Avaliando testes Boolean: E expressão de um teste Boolean pode ser de qualquer tipo (não-
Void, “vazio”). Isso pode se aplicar a qualquer objeto. O Groovy decide se considera a
expressão como sendo falsa ou verdadeira aplicando as regras mostradas na tabela seguinte,
baseada em resultados do tipo do tempo de execução. As regras são aplicadas na ordem dada,
e, uma vez que uma regra coincida, ela determina completamente o resultado.

Tabela 1. Tipos de runtime e os critérios de avaliação exigidos


Tipo runtime Critério de avaliação exigido
Boolean Valor Boolean correspondente é verdadeiro
Matcher O combinador tem uma combinação
Collection A coleção não está vazia
Map O mapa não está vazio
String, GString A string não está vazia
Number, Character O valor não é zero
Nenhum dos acima A referencia ao objeto não é nula

Exemplos:

// Valores Boolean são triviais:


assert true
assert !false

// Matches precisam combinar (match)


assert („a‟ =~ / ./)
assert ! („a‟ =~ /b/)

// Coleções não podem estar vazias


assert [1]
assert ![]

// Mapas não podem estar vazios


assert [„a‟ : 1]
assert ![:]

// Strings não podem estar vazios


assert „a‟
assert !‟‟

// Números de qualquer tipo não podem ser zero


assert 1
assert 1.1
assert 1.2f
assert 1.3g
assert 2L
assert 3G
assert !0

// Qualquer outro valor não pode ser nulo


assert new Object()
assert !null

6.2.7. Estruturas Condicionais


Avaliam um teste Boolean e fazem uma escolha sobre o que fazer a seguir, baseado se o
resultado foi verdadeiro ou falso. If e if/else funcionam exatamente como em Java, e as
limitações do bloco também são idênticas como em Java.

if (false) assert false // If com uma linha


if (null)
{ // Bloco que se inicia com uma nova linha
assert false
}
else
{
assert true
}
Operador condicional abreviado ?, também idêntico ao em Java:
def result = (1==1) ? „ok‟ : „failed‟
assert result == „ok‟
6.2.8. Estrutura switch
Também tem construção idêntica ao caso de Java, e sua lógica também é idêntica ao sentido
que a manipulação lógica recai no próximo caso a não ser que tenha saída explícita (com a
terminação break)

def log = „‟
switch (a) {
case 0 : log += „0‟
case 1 : log += „1‟
case 3 : log += „2‟ ; break
case 4 : log += „default‟
}
assert log == „12‟

6.2.9. Switch com Classificadores


Um classificador é eleito como uma switch caso ele implemente o método isCase. De modo
genérico, temos:

switch (candidate) {
case classifier1 : handler1() ; break
case classifier2 : handler2() ; break
default : handlerDefault()
}

Que é aproximadamente equivalente aos comandos condicionais:

if (classifier1.isCase(candidate)) handler1()
else if (classifier2.isCase(candidate)) handler2()
else handlerDefault()
Isso permite classificações expressivas e mesmo alguns usos pouco convencionais
com classificadores misturados. Diferente dos casos de constantes do Java, o candidato pode
muito mais do que um classificador. Isso significa que a ordem dos casos é importante em
Groovy, visto que ele não afeta o comportamento em Java. A listagem a seguir dá um
exemplo de múltiplos tipos de classificadores. Depois de ter checado que o nosso número 10
não é zero, não está na esclaa 0..9, nem na lista [8,9,11], nem é do tipo Float e não é uma
integral múltipla de 3, nós finalmente descobrimos que ele é feito de dois caracteres.
switch (10) {
case 0 : assert false ; break
case 0..9 : assert false ; break
case [8,9,11] : assert false ; break
case Float : assert false ; break // Caso de tipo
case {it%3 == 0} : assert false ; break // Caso de closure
case ~/../ : assert true ; break // Caso de expressão regular
default : assert false ; break
}

Para aumentar o poder da construção switch, é essencial saber as implementações


isCase disponíveis. A seguir há uma lista das implementações mais conhecidas no GDK:
Tabela 2. Lista das implementações mais conhecidas no Groovy Development Kit
Classe a.isCase(b) implementado como
Object a.equals(b)
Class a.isInstance(b)
Collection a.contains(b)
Range a.contains(b)
Pattern a.matcher(b.toString()).matches()
String A==null && b==null || a.equals(b)
Closure a.call(b)
6.2.10. Looping com while
Construção como sua contraparte Java. A única diferença é a vista anteriormente: o poder das
expressões de teste Boolean do Groovy.

def list = [1, 2, 3]


while (list) {
list.remove(0)
}
Assert list == []

6.2.11. Looping com for


O Groovy torna o loop for uma iteração com maior facilidade, apesar de ser amplamente
utilizado, sua estrutura não é facilmente expressa. Loops Groovy seguem a seguinte estrutura:

for (variable in iterable) { body }

em que variable pode opcionalmente ter um tipo declarado. O loop Groovy for itera sobre a
iterável. Iteráveis usafas frequentemente são escalas, coleções, mapas, arrays, iteradores e
enumeradores. De fato, qualquer objeto pode ser um iterável.

Exemplos de loops for:

// Tipificado, sobre escala de campo de texto, sem chaves


def store = „‟
for (String i in „a‟..c‟‟) store += i
assert store == „abc‟

// Não tipificado, sobre lista e coleções, chaves


store = „‟
for (i in [1, 2, 3]) {
store += i
}
assert store == „123‟

// Não tipificado, sobre IntRange meio-exclusiva, chaves


def myString == „Equivalent do Java‟
store = „‟
for (i in 0 ..< myString.size() ) {
store += myString[i]
}

// Não tipificado, sobre campo de texto como coleção, chaves


assert store == myString
store = „‟
for (i in myString) {
store += i
}
assert store == myString

Todos os loops Groovy possuem os terminadores return, break e continue, como em


Java, com a única diferença que a palavra-chave return é opcional para a última expressão em
um método ou closure. Se for omitida, o valor de retorno vai ser o mesmo valor da última
expressão.
Sobre tipos, como já citado, todos os tipos são tratados como objetos, e as
declarações são tal qual em Java, porém, Groovy oferece a escolha de atribuir tipos
explicitamente exatamente e também declarações de tipos estáticos opcionais e o tipo
dinâmico usado em tempo de execução. A palavra chave def é usada para indicar que nenhum
tipo particular é exigido.
Tabela 3. Declaração de tipos
Indicação Tipo de valor Comentário
def a = 1 java.lang.Integer Tipo implícito
def b = 1.0f java.lang.Float
int c = 1 java.lang.Integer Tipo explícito usando os
float d = 1 java.lang.Float tipos de dados primitivos
integer e = 1 java.lang.Integer Tipo explícito usando nomes
String f = „1‟ java.lang.String de tipos de referencia

Assim como em Java, Groovy suporta declarações de tipos (classes, interfaces),


métodos, variáveis, constantes, pacotes e declarações seqüenciais e recursivas, porém não
possui declarações colaterais. As estruturas das declarações se assemelha a Java, tanto de
objetos, classes e interfaces quanto de métodos, e as duas liguagens possuem as mesmas
estruturas bindables (valores, variáveis locais, instancia e variáveis de classes, métodos,
classes e pacotes).
Declarações de métodos seguem os mesmos conceitos que os para variáveis: Os
modificadores usuais Java podem ser usados; declarar um tipo de retorno é opcional; e, se
nenhum modificador ou tipo de retorno for fornecido, a palavra chave def preenche a lacuna.
Quando a palavra-chave é usada, o tipo de retorno é julgado não ter sido escolhido (apesar de
que ele ainda pode não ter tipo de retorno, equivalente a void). A visibilidade padrão dos
métodos é pública, e a passagem de objetos nos parâmetros é por referencia, assim como em
Java, e os parâmetros podem ou não ser definidos:

class SomeClass {
static void main (args){ // public implícito
def some = new SomeClass()
some.publicVoidMethod()
assert „hi‟ == some.publicUntypedMethod()
assert „ho‟ == come.publicTupeMethod()
combinedMethod() // Chama o método estático da classe atual
}
void publicVoidMethod() {
}
def publicUntypedMethod() {
return „hi‟
}
String publicTypedMethod() {
return „ho‟
}
protected static final void combinedMethod() {
}
static method(String args) {
return „typed‟
}
static method (arg1, Number arg2) { //sobrecarga de métodos
return „two args‟
}
}

7. PROCEDIMENTOS DA LINGUAGEM
Como citado anteriormente, os procedimentos em Groovy se dão da mesma forma
que em Java (métodos), e acessados da seguinte forma:

objectReference.methodName()

Porém, este formato impõe restrições para nomes de método; por exemplo, eles
podem não conter caracteres especiais, como menos (-) ou ponto (.). Contudo, o Groovy lhe
permite usar esses caracteres em nomes de métodos se você colocar aspas ao redor do nome:
objectReference.„my.method-Name‟()

O objetivo dessa característica é suportar usos onde o nome do método de uma


chamada se torna parte da funcionalidade.

7.1. Desreferencia segura com o operador ?


Quando uma referencia não aponta nenhum objeto específico, seu valor é null. Quando se
chama um método ou se acessa um campo em uma referencia nula, um NullPointerException
(NPE) é jogado. Isso é útil para proteger o código de trabalhar em pré-condições indefinidas,
mas pode facilmente tomar o caminho do código do “melhor esforço” que deve ser executado
para referencias válidas e apenas silenciar outras de outra forma.
A seguir um exemplo mostra várias aproximações alternativas para proteger o código
de NPE`s. Groovy fornece o operador adicional ?, para desdiferencia segura. Quando a
referencia antes do operador é uma referencia nula, a avaliação da expressão atual pára, e null
é retornado, e a desreferencia segura é a forma mais elegante e compacta, além de expressiva,
comparado com outras soluções:

def map = [ a : [b : [ c : 1 ] ] ]
assert map.a.b.c == 1

if (map && map.a && map.a.x) { // Proteção com if: avaliação de curto-circuito
assert map.a.x.c == null
}

try { // Proteção com try / catch


assert map.a.x.c == null
} catch (NullPointerException npe) {
}
Assert map?.a?.x?.c == null // Desreferencia segura.
Para a aplicação das normas de qualidade dentro da empresa, a empresa disponibiliza
treinamento dentro da própria para seus funcionários, e aqueles que realizarem treinamentos
externos (apoiados pela empresa), se responsabilizam por multiplicar o conhecimento aos
outros funcionários ministrando cursos dentro da própria empresa, recebendo pagamento
referente à hora-aula ministrada.

8. GROOVY E ORIENTAÇÃO A OBJETOS


Groovy não apenas realça o Java tornando-o uma linguagem de script, mas também fornece
novas características OO, características de orientação dinâmica a objetos. Definição de
classes em Groovy é quase idêntica ao Java; classes são declaradas usando-se a palavra-chave
class e podem conter campos, construtores, inicializadores e métodos. Métodos e construtores
podem eles próprios utilizar variáveis locais como parte de seu código de implementação.
Scripts são diferentes – oferecendo flexibilidade adicional, mas com algumas restrições,
também. Eles podem conter código, definição de variáveis e métodos assim como definições
de classe.
Definir o tipo de uma variável em Groovy é opcional. Contudo, o identificador não
pode ficar sozinho na declaração. Quando nenhum tipo e nenhum modificador é dado, a
palavra-chave def precisa ser usada como uma substituição, efetivamente indicando que o
campo ou a variável não foi digitada (apesar de que, sob as cobertas, ela será declarada como
do tipo Object).
Exemplo de declaração de classe e de variáveis:

Class SomeClass {
public fieldWithModifier
String typedField
def untypedField
protected field1, field2, field3
private assignedField = new Date()
static classField
public static final String CONSTA = „a‟, CONSTB = „b‟
def someMethod(){
def localUntypedMethodVar = 1
int localTypedMethodVar = 1
def localVarWithoutAssignment, andAnotherOne
}
}
A relação entre arquivos e declarações de classe não é fixa como no Java. Arquivos
Groovy podem conter qualquer numero ou declarações de classe públicas de acordo com as
seguintes regras:
 Se um arquivo Groovy não contém declaração de classe, ele é
manipulado como um script; isto é, ele é transparentemente dobrado em uma classe do
tipo Script. Essa classe gerada automaticamente tem o mesmo nome do arquivo de
script fonte (sem a extensão). O conteúdo do arquivo é dobrado em um método run, e
um método adicional é construído para facilmente inicializar o script.
 Se um arquivo Groovy contém exatamente uma declaração de classe
com o mesmo nome do arquivo (sem a extensão), então há a mesma relação um-a-um
que em Java.
 Um arquivo Groovy pode conter múltiplas declarações de classe de
qualquer visibilidade, e há uma regra de reforço que qualquer uma delas precisa
coincidir com o nome do arquivo. O compilador groovyc felizmente cria arquivos
*.class para todas as classes declaradas em tal arquivo. Se você quer invocar seu script
diretamente, por exemplo utilizando Groovy na linha de comando ou dentro de um
IDE, então a primeira classe dentro de seu arquivo deve ter um método main.
 Um arquivo Groovy pode conter declarações de classe misturadas e
código de script. Nesse caso, o código de script irá se tornar a principal classe a ser
executada, então não declare uma classe por si tendo o mesmo nome de um arquivo
fonte.
A orientação a objetos em Groovy traz como pontos positivos o encapsulamento dos
dados, provendo assim maior segurança da informação, e o reuso de código, como muitos
falam, não é necessário “reinventar a roda” toda vez que for utilizá-la.

9. SEQÜENCIADORES
Em relação aos seqüenciadores, Groovy é muito similar ao Java. Assim como em Java,
Groovy não permite o uso de goto, apesar de que ela seja uma palavra reservada. Quanto a
return, break e continue, a diferença é que a palavra-chave return é opcional para a última
expressão em um método ou closure. Se ela for omitida, o valor de retorno é aquele da última
expressão. Métodos com tipo explícito de retorno void não retornam um valor.
Exemplo de break e continue:

def a = 1
while(true) {
a++
break
}
assert a == 2
for(i in 0..10) {
if(i==0) continue
a++
if(i > 0) break
}
assert a == 3

Manipulação de exceções é exatamente como em Java e segue a mesma lógica.


Como no Java, você pode especificar uma sequência completa throw/try-catch-finally de
blocos, ou apenas try-catch, ou apenas try-finally. Diferente das outras estruturas de controle,
chaves são exigidas ao redor dos corpos de bloco contendo ou não mais do que uma
indicação. A única diferença entre Java e Groovy em termos de exceções, é que declarações
de exceções na assinatura do método são opcionais, mesmo para exceções verificadas.
Exemplo de throw, try, catch e finally:

def myMethod() {
throw new IllegalArgumentException()
}

def log = []
try {
myMethod()
}catch(Exception e) {
log << e.toString()
}finally {
log << 'finally'
}
assert log.size() == 2

Apesar da tipificação opcional no resto do Groovy, um tipo é mandatário na


expressão catch.
Não há aviso em tempo de compilação ou de execução do Groovy quando exceções
checadas não são declaradas. Quando uma exceção checada não é manipulada, é propagado
que a execução pára como uma RuntimeException.

10. CONCLUSÃO
A linguagem Groovy é uma excelente ferramenta para gerar código interpretado em Java, e
traz algumas funcionalidades interessantes na programação usual como o suporte nativo a
listas e mapas, e também expressões regulares, além de ter suporte e acesso a qualquer API de
Java, uma das linguagens mais usuais. Porém, um dos grandes benefícios de uma linguagem
script para a Java Virtual Machine é a possibilidade de integrar um programa Java com scripts
e Groovy.
Porém, a linguagem Groovy também possui algumas deficiências, como
performance. Não espere de um script Groovy uma performance como a de um programa
Java. A equipe do projeto está trabalhando em seus compiladores, mas a performance quase
sempre vai ser inferior a de uma aplicação normal.
Depurar um programa em Groovy costuma ser meio frustrante. As mensagens de erro
retornadas pelo compilador podem não parecer ter sentido algum (algo que realmente deve ser
melhorado), mas muito disso se deve á sintaxe relaxada da linguagem (quando se tem tantas
opções, é difícil dizer quando algo está errado).
Groovy possui plugins para as mais famosas IDE`s para Java, porém ainda em
estágio inicial, porém não comprometendo sua usabilidade.

REFERÊNCIAS

[1] KÖNIG, Dierk; GLOVER, Andrew; LAFORGE, Guillaume; SKEET, Jon. Groovy in Action.
Nova York, NY. Manning Publications Co., 2007.

[2] BARCLAY, Kenneth; SAVAGE, John. Groovy Programming an Introduction for Java Developers.
São Francisco, CA. Morgan Kaufmann Publish, 2007.

[3] WATT, David A.; FINDLAY, William; Programming Languanges Design Concepts, Glasgow, IR.
John Wiley & Sons, Ltd, 2004.

Você também pode gostar