Tipos de dados em Groovy
Neste artigo vamos analisar os tipos de dados que estão disponíveis na linguagem de programação Groovy. Veremos na prática como alguns tipos da plataforma Java influenciaram a linguagem e são até mesmo usados no Groovy.
O Groovy foi criado por volta de 2003 como uma linguagem dinâmica e com o objetivo de rodar na JVM, ou seja, compilada diretamente para bytecodes, com a elegância de linguagens como Python e Ruby e ao mesmo tempo com a capacidade de interagir com código Java já existente. Assim, ele conta com vários recursos e sintaxe mais simples que a do Java, mesmo sofrendo muita influência dos tipos de dados disponíveis em Java, como veremos isso no decorrer do artigo.
Para acompanhar os exemplos que serão apresentados neste artigo é necessário que o leitor possua a linguagem Groovy instalada em sua máquina. Caso ainda não tenha, o processo de instalação é simples: apenas baixe o zip no site da linguagem e descompacte-o em um diretório de sua preferência. Além disso, será necessário configurar as variáveis de ambiente GROOVY_HOME e PATH para que os comandos da linguagem sejam encontrados em um terminal ou prompt de comando.
A variável GROOVY_HOME deve conter como valor o caminho para a pasta onde o Groovy foi descompactado:
GROOVY_HOME=c:\groovy-2.4.5
E a variável PATH deve conter o caminho para a pasta bin que está localizada dentro do diretório do Groovy:
PATH=JAVA_HOME/bin;GROOVY_HOME/bin
Para testar a instalação basta digitar no terminal ou prompt o seguinte comando:
$ groovy --version
Ele deve ter como resposta a versão da linguagem instalada:
=>Groovy Version: 2.4.5 JVM: 1.8.0_74 Vendor: Oracle Corporation OS: Linux
Junto com a linguagem temos o Groovy Console, que vai ajudar na execução dos códigos. Conheceremos mais dela na seção a seguir.
Groovy Console
Essa ferramenta é usada para compilar, executar e mostrar o resultado da execução de códigos Groovy. Para executá-la basta digitar no console o comando groovyConsole e como resultado uma nova janela será mostrada, conforme a Figura 1. Perceba que ela contém um campo semelhante a um editor de texto e logo abaixo um display para apresentar as saídas do código executado
Figura 1. Groovy console.
A execução do código pode ser feita
de duas maneiras: pressionando o botão
Tipos primitivos
Variáveis de tipos primitivos são aquelas que guardam informações mais simples ou básicas, além de fazer chamadas aos métodos. Não existem tipos primitivos em Groovy, ou seja, todas as variáveis são objetos, até mesmo valores literais escritos diretamente no código como, por exemplo, true, false, 10. Isso pode ser comprovado por meio da ferramenta Groovy Console através do teste com o código da Listagem 1.
Listagem 1. Código chamando métodos em variáveis aparentemente primitivas.
println 10.class
println 100.5.class
println true.class
println false.class
Perceba que estamos acessando uma propriedade a partir de um valor que parece um primitivo. Isso pode parecer estranho, especialmente para programadores Java, mas lembre-se que esses valores são na verdade referências a objetos. A seguir vemos a saída de execução deste código:
=> class java.lang.Integer
=> class java.math.BigDecimal
=> class java.lang.Boolean
=> class java.lang.Boolean
Valores literais
São aqueles que estão explicitamente dispostos no código, como os apresentados na Listagem 1, que não foram resultado de uma operação ou informados durante a execução do programa. Existem tipos pré-definidos para valores literais e na Tabela 1 vemos alguns exemplos de valores literais com seus respectivos tipos.
|
Classe |
Valor literal de exemplo |
|
java.lang.Long |
1000L |
|
java.lang.Integer |
100 |
|
java.lang.Float |
1.0F |
|
java.lang.Double |
100D |
|
java.math.BigDeciamal |
1000.50 |
|
java.math.BigInteger |
123G |
Tabela 1. Tipos pré-definidos
Note que para obter variáveis do tipo long, flot, double e big integer é necessário informar isso passando os sinais “L”, “F”, “D” e “G”, respectivamente, já que estes não são os tipos padrões para os valores literais.
Tipagem dinâmica e estática
Em Groovy, especificar o tipo de uma variável é opcional: caso o tipo não seja explicitamente informado, a linguagem vai inferir o seu tipo, baseando-se nas caracterizas do valor passado. Isso pode ser observado na Listagem 5, onde vemos um método avaliarTipo que testa o tipo da variável passada.
Listagem 5. Código para teste de tipo da variável.
idade = 20
avaliarTipo(idade)
string = "Hello!"
avaliarTipo(string)
populacao = 100000000L
avaliarTipo(populacao)
orcamento = 200.00d
avaliarTipo(orcamento)
preco = 200.00
avaliarTipo(preco)
def avaliarTipo(variavel){
switch(variavel.getClass()){
case Integer:
println("A variável foi avaliada como Inteiro")
break
case BigDecimal:
println("A variável foi avaiada como BigDecimal")
break
case Double:
println("A variável foi avaliada como Double")
break
case String:
println("A variável foi avaliada como String")
break
case Long:
println("A variável foi avaliada como Long")
break
case BigInteger:
println("A variável foi avaliada como BigInteger")
break
}
}
A saída de execução desse código é vista a seguir, onde para cada chamado do método avaliarTipo uma linha foi impressa informado o tipo da variável passada.
=> A variável foi avaliada como Inteiro
=> A variável foi avaliada como String
=> A variável foi avaliada como Long
=> A variável foi avaliada como Double
=> A variável foi avaiada como BigDecimal
Além da tipagem dinâmica, o Groovy também permite ao programador especificar explicitamente os tipos das variáveis, passando o tipo antes do seu nome, como mostra a Listagem 6.
Listagem 6. Definição de variáveis explicitamente tipadas.
Integer idade = 10
Double valor = 1.0d
String nome = “José Camilo”
A vantagem nessa tipagem é que o compilador não necessitará executar procedimentos para definir o tipo da variável, logo essa estratégia de código é ligeiramente mais rápida.
Outro ponto a destacar é que, uma vez definidos, os tipos não podem ser alterados, porque uma variável do tipo string nunca poderá armazenar um valor numérico e vice-versa, como mostra o exemplo da Listagem 7.
Listagem 7. O tipo de uma variável Groovy não pode ser alterado após a sua definição.
Integer preco = 1000
println preco.class
preco = "Mil Reais"
O código defini uma varável preco do tipo inteiro e atribui a ela o valor 1000; depois de imprimir o seu tipo, o código tenta atribuir um valor do tipo string e então uma exceção é lançada, como mostra a saída a seguir:
=> class java.lang.Integer
=> Exception thrown
=> org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'Mil Reais' with class 'java.lang.String' to class 'java.lang.Integer'
at ConsoleScript34.run(ConsoleScript34:5)
String Ranges
Ranges são intervalos de valores, ou seja, objetos que armazenam valores específicos. Por exemplo: um range pode armazenar um valor de 1 a 10, ou até mesmo de caracteres como de a até z. Esse tipo pode ser definido de duas formas, como mostra a Listagem 8. A variável a define um range que inclui o último elemento informado; para o range armazenado em b o último elemento não é incluído: isso é definido por meio do sinal <.
Listagem 8. Sintaxe de declaração para ranges.
a = [primeiro_elemento] . . [ultimo_elemento_incluso]
b = [primeiro_elemento] . . < [ultimo_elemento_nao_incluso]
Para percorrer os elementos de um range é possível usar o loop for ou até mesmo o método each disponível para objetos do tipo range, como mostra a Listagem 9. Veja o uso dessas estruturas para percorrer os itens de três objetos range's> perceba que um deles é um intervalo de letras e não de números.
Listagem 9. Código de exemplo para percorrer range'
println("INTERVALO1")
intervalo1 = 1..15
for(int i = 0; i < intervalo1.size(); i++){
print("${intervalo1[i]} ")
}
println("INTERVALO2")
intervalo2 = 15..<30
for(item in intervalo2){
print("$ ")
}
println("ALFABETO")
alfabeto = 'a'..'z'
alfabeto.each{letra -> print("$ ")}
O range intervalo1 armazena os valores de 1 até 15, e ele foi percorrido usando um for clássico ou tradicional, idêntico ao do Java. O intervalo2 foi percorrido usando um loop for simplificado, que apenas recebe cada elemento do range em uma determinada variável, no caso, a variável item. O range que armazena as letras de 'a' até 'z' foi percorrido utilizando o método each, que recebe um bloco de código para manipular o item em iteração. A saída do código é exibida a seguir:
=> INTERVALO1
=> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
=> INTERVALO2
=> 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
=> ALFABETO
=> a b c d e f g h i j k l m n o p q r s t u v w x y z
Além de letras, como mostrado no último exemplo, é possível também definir intervalos de datas, como mostra a Listagem 10.
Listagem 10. Exemplo de objeto range armazenando intervalo de datas.
data1 = new Date().parse("dd/MM/yyyy", "01/01/2016")
data2 = new Date().parse("dd/MM/yyyy", "10/01/2016")
intervalo = data1..data2
intervalo.each{data -> println(data.format('dd/MM/yyyy'))}
Esse código utiliza o método each para percorrer o intervalo de datas e imprimir cada uma delas. A saída deste código é apresentada a seguir:
=> 01/01/2016
=> 02/01/2016
=> 03/01/2016
=> 04/01/2016
=> 05/01/2016
=> 06/01/2016
=> 07/01/2016
=> 08/01/2016
=> 09/01/2016
=> 10/01/2016
Range's também podem ser usados nas instruções case do bloco condicional switch. Se o valor passado estiver dentro do intervalo definido pelo range o bloco de código associado é executado, como mostra a Listagem 11.
Listagem 11. Exemplo de uso de range's em instruções switch.
def definirIdade(idade){
switch(idade){
case 0..10:
println("Você tem entre 0 e 10 anos.")
break
case 11..17:
println("Você tem entre 11 e 17 anos.")
break
case idade >= 18:
println("Você tem 18 anos ou mais.");
break
}
}
Os range's também dispões de vários métodos utilitários que podem ajudar na manipulação das informações. Veja na Listagem 12 o uso dos métodos contains, size e as propriedades to e from.
Listagem 12. Exemplo de uso dos métodos contains e size e propriedades from e to.
intervalo1 = 'a'..'e'
if(intervalo1.contains('d')){
println('O intervalo contém a letra d')
}
println "O intervalo tem ${intervalo1.size()} elementos"
println "O primeiro elemento é '${intervalo1.from}'"
println "O último elemento é '${intervalo1.to}'"
O método contains verifica se o parâmetro passado está contido no intervalo e retorna true ou false. O método size retorna a quantidade de elementos encontrados no intervalo. Já as propriedades from e to retornar, respectivamente, o primeiro e o último elemento do range. A saída do código é mostrada a seguir:
=> O intervalo contém a letra d
=> O intervalo tem 5 elementos
=> O primeiro elemento é 'a'
=> O último elemento é 'e'
Listas
As listas do Groovy aproveitam o que há de melhor nos arrays do Java, bem como na API de collection, como as classes ArrayList e LinkedList. Para criar uma lista em Groovy basta seguir a sintaxe:
lista = [item1, item2, item3, item4, itemN]
Por padrão, essas listas são instâncias da classe java.util.ArrayList . Veja na Listagem 14 o código que imprime o tipo de uma lista.
Listagem 14. Instanciando e imprimindo o tipo de uma lista.
nomes = ["jose", "joao", "silva", "souza"]
println nomes.class
O código exibe o seguinte resultado:
=> class java.util.ArrayList
É possível especificar o tipo de lista que se deseja criar no momento do processo de instância. Veja a seguir um exemplo de código criando uma lista do tipo LinkedList:
lista = new LinkedList();
println lista.class
Esse código imprime como resultado o tipo da lista criada, como mostrado a seguir:
=> class java.util.LinkedList
Além disso, também é possível criar uma lista a partir de um range, como exibido no código a seguir:
range = 1..10
List lista = range.toList()
Operações com Listas
O método addAll permite adicionar todos os itens de uma lista em outra, como mostra o exemplo da Listagem 15.
Listagem 15. Exemplo de uso do método addAll.
nomes1 = ['souza','silva','carlos','joao']
println nomes1.size() //4
nomes2 = ['camilo','machado','mateus','paulo']
nomes1.addAll(nomes2)
println nomes1.size() //8
Para acessar elementos de uma lista pode ser usado o índice do elemento entre colchetes “[]”, bem como passar o índice como parâmetro para o método get. Veja um exemplo na Listagem 16.
Listagem 16. Acessando elementos de uma lista.
precos1 = [10, 20, 30.0, 40]
println "Elemento da posição 0: ${precos1[0]}"
println "Elemento da posição 3: ${precos1.get(3)}"
Esse código apresenta na saída o resultado a seguir; perceba que os índices ou posições das listas iniciam em 0:
=> Elemento da posição 0: 10
=> Elemento da posição 3: 40
Também é possível criar uma lista que contenha outras listas como itens, que pode representar uma matriz ou lista multidimensional:
lista = [[1,2,3],[4,5,6],[7,8,9]]
Assim como nos range's, o método size() pode ser usado para recuperar o tamanho de uma lista. Com os métodos get e size já analisados é possível percorrer uma lista, como mostra o exemplo da Listagem 17.
Listagem 17. Uso dos métodos get e size
lista = [1,2,3,4,5,6,7,8,9]
for(int i = 0; i < lista.size();i++){
print lista.get(i)
}
Também é possível acessar os dados de uma lista passando como parâmetro um range, como mostra a Listagem 19.
Listagem 19. Acessando itens de uma lista por um range.
clientes = ['joao', 'silva', 'oliveira', 'neto', 'pereira', 'manoel']
intervalo = 2..5
println clientes[intervalo]
Neste caso apenas os itens com índices entre 2 e 5 vão ser impressos no display de saída, como mostra o bloco a seguir:
=> [neto, pereira, manoel]
Ainda é possível coletar itens específicos de listas. Isso é feito passando os índices dos itens desejados separados por vírgula, como mostra o código a seguir:
clientes = ['joao', 'silva', 'oliveira', 'neto', 'pereira', 'manoel', 'carlos']
println clientes[0,2,5,6]
Já no caso da execução deste código apenas os itens com os índices 0, 2, 5 e 6 são impressos:
=> [joao, oliveira, manoel, carlos]
Usando essa mesma estratégia é possível remover elementos de uma lista, como mostra a Listagem 20.
Listagem 20. Exemplo de remoção de itens com ragen's.
clientes = ['joao', 'silva', 'oliveira', 'neto', 'pereira', 'manoel', 'carlos']
clientes[0..2] = []
println clientes
Esse código imprimirá a lista apresentada a seguir; note que os índices de 0 até 2 foram removidos:
=> [neto, pereira, manoel, carlos]
É possível adicionar e remover itens em listas de várias maneiras. Na Listagem 21 vemos alguns exemplos de código adicionando e removendo elementos em listas.
Listagem 21. Exemplo de código para adicionar e remover itens de listas.
clientes = []
clientes += 'jose'
clientes += ['elton', 'maria', 'lucena']
clientes << 'carvalho'
clientes -= 'jose'
println clientes
Note que foram usados os operadores += e << para adicionar elementos e o operador -= para exclui-los da lista. Ao ser executado o código anterior gera a seguinte saída:
=> [elton, maria, lucena, carvalho]
Mapas
São estruturas bastante semelhantes as listas: a diferença principal entre essas duas estruturas é que os elementos de um mapa não acessíveis por um índice, mas sim por uma chave, que pode ser qualquer objeto. A sintaxe para a declaração de um map está descrita a seguir:
map = [chave1: valor1, chave2: valor2, chave3: valor3, chaveN: valorN]
Para adicionar ou remover elementos em um map pode-se usar a notação descrita na Listagem 22.
Listagem 22. Exemplo de código para adicionar ou remover elementos de um map.
map["nome"] = "daniel"
map["sobrenome"] = "tavares"
map["email"] = "jdanieltrs1@gmail.com"
map["endereco"] = "Rua do Construtor José Sabino"
map["endereco"] = null
println map
O código usou a notação “[chave] =” para configurar um valor para determinada chave. Para remover determinado valor uma atribuição com “null” foi executada.
Uma das maneiras mais fáceis de percorrer ou ler dados de um map é utilizar o método each que funciona de uma forma um pouco de diferente desse mesmo métodos para listas. Veja na Listagem 23 o funcionamento deste método.
Listagem 23. Usando o método each em um map.
map["nome"] = "daniel"
map["sobrenome"] = "tavares"
map["email"] = "jdanieltrs1@gmail.com"
map["endereco"] = "Rua do Construtor José Sabino"
map.each{ entrada ->
println "${entrada.key} - ${entrada.value}"
}
Perceba que no método each usamos as propriedades key e value para recuperar a chave e o valor de cada item do map. A saída desse código é exibida a seguir.
=> nome - daniel
=> sobrenome - tavares
=> email - jdanieltrs1@gmail.com
=> endereco - Rua do Construtor José Sabino
Essa foi uma pequena introdução aos principais tipos de dados da linguagem Groovy e suas principais características. Saber destes pontos é de suma importância antes de entrar em detalhes mais profundos sobre a linguagem. Assim, vemos que a manipulação de informações nas estruturas mais usadas no Groovy é algo relativamente simples, e mais ainda para quem já é desenvolvedor Java, pois muito dessa se aproveita dentro do Groovy.
Referências
Documentação Groovy
http://www.groovy-lang.org/documentation.html
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo