Arquivo → January, 2009
Como descobrir o nome daquela coluna em uma planilha?
Suponhamos que você esteja trabalhando na geração de uma planilha usando POI ou Jxl ou OdfEasy ( :-) ). Um problema que surge é: como saber qual o nome da coluna 34?
Encontrei uma função feita em C# que, traduzida para o Java, resulta no código abaixo (ei, se encontrarem algum bug na mesma, me passem para que eu a atualize, ok?). E que será utilizada na biblioteca de utilitários do ODF Easy.
// Só por conveniencia (leia preguiça) criei uma matriz contendo todas as letras do alfabeto.
// Você é livre para criar uma alternativa mais interessante (com certeza há!)
private static String[] letras = {
"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"
};
private static String getColumn(int column)
{
if (column >= 0 && column < 26) {
return letras[column];
} else if (column > 25) {
return letras[(column / 26) - 1] + letras[column % 26];
} else
return null;
}
Como o MALDITO Access pode jogar uma JVM no chão
Este problema ocorre com as versões 5 e 6 do Java executando no sistema operacional Windows XP.
Recentemente enfrentamos um problema bastante interessante: ao instanciarmos um objeto do tipo PreparedStatement (usando como conexão a ponte JdbcOdbc padrão do Java) acessando uma base de dados Access (97), a JVM simplesmente ia pro chão. BOOM!
O erro só aparece no Windows XP, enquanto no Vista, as coisas eram executadas sem dificuldade. Como consequencia, ao analisarmos o log de crash da JVM, acabamos por perceber que o erro não era em nossa aplicação, mas sim nos drivers ODBC (vide log abaixo). Era incrível: bastava instanciar o preparedstatement no XP e… BOOM.
Analisando mais o nosso código, descobrimos o que estava dando errado. Só para simplificar o código era algo mais ou menos assim:
Connection conexao = metodoQueRetornaAConexaoComMalditoAccess97();
// bla bla bla
PreparedStatement stmt = conexao.prepareStatement("select * from tabelaMaldita"); // Aqui rolava o boom da JVM
Analisando o código, descobrimos que, no meio de “blablabla”, devido a um erro de programação, a conexão era fechada. Sendo assim, ao instanciar um novo PreparedStatement, com a mesma, o que você espera? Que seja disparada uma excessão, correto? Errado! No caso do Access 97 executando no XP (driver do Microsoft Access versão 4.0.0) ele simplesmente quebra a JVM, finalizando o processo.
Segue abaixo o log básico para aqueles que vierem a passar por esta desagradável situação:
# # An unexpected error has been detected by Java Runtime Environment: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c90100b, pid=2616, tid=948 # # Java VM: Java HotSpot(TM) Client VM (11.0-b16 mixed mode, sharing windows-x86) # Problematic frame: # C [ntdll.dll+0x100b] # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp # The crash happened outside the Java Virtual Machine in native code. # See problematic frame for where to report the bug. # --------------- T H R E A D --------------- Current thread (0x03402800): JavaThread "Thread-9" [_thread_in_native, id=948, stack(0x046c0000,0x04710000)] siginfo: ExceptionCode=0xc0000005, reading address 0x00000018 Registers: EAX=0x00000004, EBX=0x27130be0, ECX=0x7ffa5000, EDX=0x00000004 ESP=0x0470f7b8, EBP=0x0470f7d0, ESI=0x00000000, EDI=0x039d1348 EIP=0x7c90100b, EFLAGS=0x00010202 Top of Stack: (sp=0x0470f7b8) 0x0470f7b8: 746459fa 00000004 039d1374 7461139f 0x0470f7c8: 039d1374 039d1348 0470f7e0 74620b2a 0x0470f7d8: 039d1374 03402914 0470f7f4 7461822b 0x0470f7e8: 039d1348 74640000 00000000 0470f810 0x0470f7f8: 74619652 039d1348 0470f830 00000003 0x0470f808: 03fd9548 03402914 0470f828 6d36124e 0x0470f818: 039d1348 0470f830 03402800 27130be0 0x0470f828: 0470f870 00929cf1 00000000 0470f88c Instructions: (pc=0x7c90100b) 0x7c900ffb: 00 00 00 00 00 64 8b 0d 18 00 00 00 8b 54 24 04 0x7c90100b: 83 7a 14 00 75 4f f0 ff 42 04 75 19 8b 41 24 89 Stack: [0x046c0000,0x04710000], sp=0x0470f7b8, free space=317k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [ntdll.dll+0x100b] C [ODBC32.dll+0x10b2a] C [ODBC32.dll+0x822b] C [ODBC32.dll+0x9652] C [JdbcOdbc.dll+0x124e] j sun.jdbc.odbc.JdbcOdbc.allocStmt(J[B)J+0 j sun.jdbc.odbc.JdbcOdbc.SQLAllocStmt(J)J+47 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;II)Ljava/sql/PreparedStatement;+55 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;)Ljava/sql/PreparedStatement;+8 j ecm.legado.capex.importadorppex.Importador.importarTabCapex(Ljava/util/List;)V+135 j ecm.legado.capex.importadorppex.Importador.importar(Ljava/util/List;Ljava/io/File;)V+46 j ecm.legado.capex.swing.FImportadorPQ$7.run()V+212 v ~StubRoutines::call_stub Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) j sun.jdbc.odbc.JdbcOdbc.allocStmt(J[B)J+0 j sun.jdbc.odbc.JdbcOdbc.SQLAllocStmt(J)J+47 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;II)Ljava/sql/PreparedStatement;+55 j sun.jdbc.odbc.JdbcOdbcConnection.prepareStatement(Ljava/lang/String;)Ljava/sql/PreparedStatement;+8 j ecm.legado.capex.importadorppex.Importador.importarTabCapex(Ljava/util/List;)V+135 j ecm.legado.capex.importadorppex.Importador.importar(Ljava/util/List;Ljava/io/File;)V+46 j ecm.legado.capex.swing.FImportadorPQ$7.run()V+212 v ~StubRoutines::call_stub --------------- P R O C E S S --------------- Java Threads: ( => current thread ) =>0x03402800 JavaThread "Thread-9" [_thread_in_native, id=948, stack(0x046c0000,0x04710000)] 0x03316800 JavaThread "ElementEventQueue.QProcessor-1" daemon [_thread_blocked, id=1096, stack(0x03980000,0x039d0000)] 0x0340e800 JavaThread "Swing-Shell" daemon [_thread_blocked, id=2792, stack(0x03ac0000,0x03b10000)] 0x02b77800 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" daemon [_thread_blocked, id=2232, stack(0x03930000,0x03980000)] 0x033bd800 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1" daemon [_thread_blocked, id=3500, stack(0x038e0000,0x03930000)] 0x02b80000 JavaThread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0" daemon [_thread_blocked, id=864, stack(0x03890000,0x038e0000)] 0x03300000 JavaThread "Timer-0" daemon [_thread_blocked, id=4000, stack(0x03840000,0x03890000)] 0x032ad800 JavaThread "MySQL Statement Cancellation Timer" daemon [_thread_blocked, id=2768, stack(0x037f0000,0x03840000)] 0x0326b800 JavaThread "TimerQueue" daemon [_thread_blocked, id=1676, stack(0x03720000,0x03770000)] 0x003a7400 JavaThread "DestroyJavaVM" [_thread_blocked, id=1892, stack(0x008c0000,0x00910000)] 0x03219c00 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=3444, stack(0x03600000,0x03650000)] 0x02bdc400 JavaThread "AWT-Windows" daemon [_thread_in_native, id=1720, stack(0x03570000,0x035c0000)] 0x031d4400 JavaThread "AWT-Shutdown" [_thread_blocked, id=2628, stack(0x03520000,0x03570000)] 0x03211000 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=3648, stack(0x034d0000,0x03520000)] 0x02b52400 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=3440, stack(0x02e00000,0x02e50000)] 0x02b4c000 JavaThread "CompilerThread0" daemon [_thread_blocked, id=996, stack(0x02db0000,0x02e00000)] 0x02b4a800 JavaThread "Attach Listener" daemon [_thread_blocked, id=3000, stack(0x02d60000,0x02db0000)] 0x02b49400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=964, stack(0x02d10000,0x02d60000)] 0x02b44400 JavaThread "Finalizer" daemon [_thread_blocked, id=3464, stack(0x02cc0000,0x02d10000)] 0x02b3fc00 JavaThread "Reference Handler" daemon [_thread_blocked, id=1996, stack(0x02c70000,0x02cc0000)] Other Threads: 0x02b3e000 VMThread [stack: 0x02c20000,0x02c70000] [id=3920] 0x02b6e000 WatcherThread [stack: 0x02e50000,0x02ea0000] [id=3560] VM state:not at safepoint (normal execution) VM Mutex/Monitor currently owned by a thread: None Heap def new generation total 18176K, used 437K [0x169a0000, 0x17d50000, 0x17d50000) eden space 16192K, 2% used [0x169a0000, 0x16a0d5f0, 0x17970000) from space 1984K, 0% used [0x17b60000, 0x17b60000, 0x17d50000) to space 1984K, 0% used [0x17970000, 0x17970000, 0x17b60000) tenured generation total 241984K, used 11457K [0x17d50000, 0x269a0000, 0x269a0000) the space 241984K, 4% used [0x17d50000, 0x18880580, 0x18880600, 0x269a0000) compacting perm gen total 17408K, used 17398K [0x269a0000, 0x27aa0000, 0x2a9a0000) the space 17408K, 99% used [0x269a0000, 0x27a9d978, 0x27a9da00, 0x27aa0000) ro space 8192K, 63% used [0x2a9a0000, 0x2aeb3ae8, 0x2aeb3c00, 0x2b1a0000) rw space 12288K, 53% used [0x2b1a0000, 0x2b8083f8, 0x2b808400, 0x2bda0000) Dynamic libraries: 0x00400000 - 0x00424000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\javaw.exe 0x7c900000 - 0x7c9b3000 <span> </span>C:\WINDOWS\system32\ntdll.dll 0x7c800000 - 0x7c900000 <span> </span>C:\WINDOWS\system32\kernel32.dll 0x77f50000 - 0x77ffb000 <span> </span>C:\WINDOWS\system32\ADVAPI32.dll 0x77db0000 - 0x77e42000 <span> </span>C:\WINDOWS\system32\RPCRT4.dll 0x77f20000 - 0x77f31000 <span> </span>C:\WINDOWS\system32\Secur32.dll 0x7e360000 - 0x7e3f1000 <span> </span>C:\WINDOWS\system32\USER32.dll 0x77e50000 - 0x77e99000 <span> </span>C:\WINDOWS\system32\GDI32.dll 0x76360000 - 0x7637d000 <span> </span>C:\WINDOWS\system32\IMM32.DLL 0x7c340000 - 0x7c396000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\msvcr71.dll 0x6d800000 - 0x6da56000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\client\jvm.dll 0x76b20000 - 0x76b4e000 <span> </span>C:\WINDOWS\system32\WINMM.dll 0x5df40000 - 0x5df48000 <span> </span>C:\WINDOWS\system32\rdpsnd.dll 0x76330000 - 0x76340000 <span> </span>C:\WINDOWS\system32\WINSTA.dll 0x5bcb0000 - 0x5bd05000 <span> </span>C:\WINDOWS\system32\NETAPI32.dll 0x77bf0000 - 0x77c48000 <span> </span>C:\WINDOWS\system32\msvcrt.dll 0x76bd0000 - 0x76bdb000 <span> </span>C:\WINDOWS\system32\PSAPI.DLL 0x6d280000 - 0x6d288000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\hpi.dll 0x6d7b0000 - 0x6d7bc000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\verify.dll 0x6d320000 - 0x6d33f000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\java.dll 0x6d7f0000 - 0x6d7ff000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\zip.dll 0x6d000000 - 0x6d138000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\awt.dll 0x72fb0000 - 0x72fd6000 <span> </span>C:\WINDOWS\system32\WINSPOOL.DRV 0x774c0000 - 0x775fd000 <span> </span>C:\WINDOWS\system32\ole32.dll 0x773b0000 - 0x774b3000 <span> </span>C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll 0x77ea0000 - 0x77f16000 <span> </span>C:\WINDOWS\system32\SHLWAPI.dll 0x746e0000 - 0x7472c000 <span> </span>C:\WINDOWS\system32\MSCTF.dll 0x75290000 - 0x752be000 <span> </span>C:\WINDOWS\system32\msctfime.ime 0x6d220000 - 0x6d274000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\fontmanager.dll 0x7c9c0000 - 0x7d1de000 <span> </span>C:\WINDOWS\system32\shell32.dll 0x6d610000 - 0x6d623000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\net.dll 0x71a70000 - 0x71a87000 <span> </span>C:\WINDOWS\system32\WS2_32.dll 0x71a60000 - 0x71a68000 <span> </span>C:\WINDOWS\system32\WS2HELP.dll 0x6d630000 - 0x6d639000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\nio.dll 0x10000000 - 0x1000c000 <span> </span>C:\Arquivos de programas\VMware\VMware Tools\hook.dll 0x6d190000 - 0x6d1b3000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\dcpr.dll 0x77100000 - 0x7718b000 <span> </span>C:\WINDOWS\system32\OLEAUT32.DLL 0x71a10000 - 0x71a50000 <span> </span>C:\WINDOWS\system32\mswsock.dll 0x60b30000 - 0x60b88000 <span> </span>C:\WINDOWS\system32\hnetcfg.dll 0x71a50000 - 0x71a58000 <span> </span>C:\WINDOWS\System32\wshtcpip.dll 0x76f00000 - 0x76f27000 <span> </span>C:\WINDOWS\system32\DNSAPI.dll 0x76f90000 - 0x76f98000 <span> </span>C:\WINDOWS\System32\winrnr.dll 0x76f40000 - 0x76f6d000 <span> </span>C:\WINDOWS\system32\WLDAP32.dll 0x76fa0000 - 0x76fa6000 <span> </span>C:\WINDOWS\system32\rasadhlp.dll 0x68000000 - 0x68036000 <span> </span>C:\WINDOWS\system32\rsaenh.dll 0x769a0000 - 0x76a55000 <span> </span>C:\WINDOWS\system32\USERENV.dll 0x6d560000 - 0x6d569000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\management.dll 0x03b10000 - 0x03de0000 <span> </span>C:\WINDOWS\system32\xpsp2res.dll 0x71ae0000 - 0x71af2000 <span> </span>C:\WINDOWS\system32\MPR.dll 0x75f30000 - 0x75f37000 <span> </span>C:\WINDOWS\System32\drprov.dll 0x71be0000 - 0x71bee000 <span> </span>C:\WINDOWS\System32\ntlanman.dll 0x71ca0000 - 0x71cb7000 <span> </span>C:\WINDOWS\System32\NETUI0.dll 0x71c60000 - 0x71ca0000 <span> </span>C:\WINDOWS\System32\NETUI1.dll 0x71c50000 - 0x71c57000 <span> </span>C:\WINDOWS\System32\NETRAP.dll 0x71bc0000 - 0x71bd3000 <span> </span>C:\WINDOWS\System32\SAMLIB.dll 0x75f40000 - 0x75f4a000 <span> </span>C:\WINDOWS\System32\davclnt.dll 0x77900000 - 0x779f5000 <span> </span>C:\WINDOWS\system32\SETUPAPI.dll 0x76fb0000 - 0x7702f000 <span> </span>C:\WINDOWS\system32\CLBCATQ.DLL 0x77030000 - 0x770fd000 <span> </span>C:\WINDOWS\system32\COMRes.dll 0x77be0000 - 0x77be8000 <span> </span>C:\WINDOWS\system32\VERSION.dll 0x76960000 - 0x76968000 <span> </span>C:\WINDOWS\system32\LINKINFO.dll 0x76970000 - 0x76996000 <span> </span>C:\WINDOWS\system32\ntshrui.dll 0x76b00000 - 0x76b11000 <span> </span>C:\WINDOWS\system32\ATL.DLL 0x75d70000 - 0x75e01000 <span> </span>C:\WINDOWS\system32\MLANG.dll 0x6d360000 - 0x6d36d000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\JdbcOdbc.dll 0x74610000 - 0x7464d000 <span> </span>C:\WINDOWS\system32\ODBC32.dll 0x76380000 - 0x763c8000 <span> </span>C:\WINDOWS\system32\comdlg32.dll 0x03a90000 - 0x03aa8000 <span> </span>C:\WINDOWS\system32\odbcint.dll 0x6dad0000 - 0x6daeb000 <span> </span>C:\WINDOWS\system32\odbccp32.dll 0x0dd70000 - 0x0ddaa000 <span> </span>C:\WINDOWS\system32\msjtes40.dll 0x0f9a0000 - 0x0f9ab000 <span> </span>C:\WINDOWS\system32\VBAJET32.DLL 0x0f9c0000 - 0x0fa22000 <span> </span>C:\WINDOWS\system32\expsrv.dll 0x6d790000 - 0x6d798000 <span> </span>C:\Arquivos de programas\Java\jre6\bin\sunmscapi.dll 0x77a60000 - 0x77af6000 <span> </span>C:\WINDOWS\system32\CRYPT32.dll 0x77b00000 - 0x77b12000 <span> </span>C:\WINDOWS\system32\MSASN1.dll 0x4de10000 - 0x4de54000 <span> </span>C:\WINDOWS\system32\odbcjt32.dll 0x04710000 - 0x04880000 <span> </span>C:\WINDOWS\system32\msjet40.dll 0x04880000 - 0x04915000 <span> </span>C:\WINDOWS\system32\mswstr10.dll 0x5bfb0000 - 0x5bfbf000 <span> </span>C:\WINDOWS\system32\odbcji32.dll 0x03e20000 - 0x03e2d000 <span> </span>C:\WINDOWS\system32\msjter40.dll 0x03e40000 - 0x03e6c000 <span> </span>C:\WINDOWS\system32\MSJINT40.DLL 0x09770000 - 0x097bc000 <span> </span>C:\WINDOWS\system32\msrd3x40.dll VM Arguments: jvm_args: -Xms256m -Xmx256m java_command: ecm.legado.capex.swing.FImportadorPQ Launcher Type: SUN_STANDARD Environment Variables: PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Arquivos de programas\MySQL\MySQL Server 5.0\bin;C:\Arquivos de programas\Autodesk\DWG TrueView\;C:\Arquivos de programas\Java\jre6\bin USERNAME=carinha // sim, eu mudei o log OS=Windows_NT PROCESSOR_IDENTIFIER=x86 Family 6 Model 15 Stepping 8, GenuineIntel --------------- S Y S T E M --------------- OS: Windows XP Build 2600 Service Pack 3 CPU:total 1 (2 cores per cpu, 1 threads per core) family 6 model 15 stepping 2, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3 Memory: 4k page, physical 261616k(41532k free), swap 631444k(110072k free) vm_info: Java HotSpot(TM) Client VM (11.0-b16) for windows-x86 JRE (1.6.0_11-b03), built on Nov 10 2008 02:15:12 by "java_re" with MS VC++ 7.1 time: Mon Jan 05 18:21:39 2009 elapsed time: 176 seconds
Closures
O que é uma closure?
Se há um ponto em Groovy que devemos nos aprofundar, este tópico consiste na descrição das closures (aliás, seriam “as closures” ou “os closures”?). Para aqueles que programam em linguagens que não oferecem este recurso, a seguinte metáfora descreve bem o que vêm a ser esta criatura:
Uma closure por sua vez consiste em um tipo diferente de variável. Seguindo a metáfora, nosso envelope conteria não uma informação, mas sim um conjunto de instruções, resumindo: código executável.
Como vocês perceberão daqui para frente: closures consistem em um daqueles recursos que, uma vez aprendido, ficamos impressionados com o fato de havermos conseguido programar tanto tempo sem utilizá-lo.
Como declarar uma closure
Como mencionado, uma closure consiste em mais um tipo de variável e, como tal, é declarado como uma variável, tal como no exemplo abaixo:
class ClasseBoba {
// bla bla bla pra cima
def closure = {
println "Sou uma closure"
}
// bla bla bla pra baixo
}
Como pode ser percebido, uma closure é definida quase que exatamente qualquer variável que conhecemos. A única diferença está na sintaxe. Ao lado direito da declaração, ao invés de incluirmos um valor, estamos incluindo um bloco de código executável. No caso, a closure ao ser invocada irá imprimir no console o texto “Sou uma closure”
Closures, assim como qualquer método, também possuem parametros. Caso nenhum parametro seja declarado (como no exemplo acima), estará disponível no bloco de código da closure uma variável implícita chamada it. Podemos portanto incrementar o exemplo tal como farei abaixo:
class ClasseBoba {
// bla bla bla pra cima
def closure = {
println "Sou uma closure que recebeu como parâmetro o valor de ${it}"
}
// bla bla bla pra baixo
}
Caso nenhum parâmetro seja passado para a closure, ela irá imprimir algo como
Sou uma closure que recebeu como parâmetro o valor de NULL.
Já o código abaixo, imprimiria de outra maneira:
def instancia = new ClasseBoba()
instancia.closure("qualquer coisa")
// Será impresso aqui exatamente
//"Sou uma closure que recebeu como parâmetro o valor qualquer coisa"
Óbviamente, uma closure pode receber também mais de um parâmetro, tal como exposto no exemplo abaixo:
def soma = {a, b ->
a + b}
Como pode ser visto no exemplo: se quisermos declarar os parâmetros de uma closure, estes estarão declarados no início do bloco. Finalizada a declaração dos atributos (você pode definir os tipos dos parâmetros se quiser também), segue a sequencia de caracteres “->”, que indica o início do bloco de código em questão.
No caso deste exemplo, criamos uma closure que faz a soma de duas variáveis.
Também é possível modificar o nome do parâmetro de uma closure, tal como no exemplo abaixo:
def closureBoba = {parametro ->
println """Como pode ser visto, o parametro único não precisa se chamar it.
Na realidade, pode ter o nome que você quiser.
A propósito, recebi o valor de ${parametro}""" }
Como referenciar uma closure
Tal como mencionei no início, uma closure nada mais é do que uma variável. Na realidade, trata-se de uma instância da classe groovy.lang.Closure. Sendo assim, você a referencia da mesma maneira que faria com qualquer atributo/variável convencional, tal como no exemplo abaixo:
class Classe1 {
def closureClasse1
}
class Classe2 {
def closureClasse2
}
def closure = {
println "Sou uma closure bem promíscua"
}
Classe1 classe1 = new Classe1()
Classe2 classe2 = new Classe2()
classe1.closure = closure
classe2.closure = classe1.closure
O exemplo faz o seguinte: primeiro define duas classes (Classe1 e Classe2) e, em seguida, implementa uma closure bem simples.
Instanciadas tanto classe1 quanto classe2, primeiro definimos que a closure de classe1 será closure. Em seguida, definimos que a closure de classe2 será a mesma closure de classe1.
Perceberam que bacana? Com closures, podemos mudar o comportamento de nossas classes de uma maneira incrívelmente simples!
Como executar uma closure
A execução de uma closure é exatamente igual a execução de qualquer outro método Groovy, tal como pode ser visto no exemplo abaixo:
def soma = {a, b -> a + b}
def closureSimples = {"Sou simples demais"}
def closureOla = {"Olá ${it}"}
soma(3, 4) // imprimirá 7
closureSimples() // imprime "Sou simples demais"
closureOla("Kico") // imprime "Olá Kico"
Os parênteses são obrigatórios na execução de uma closure.
Como executar uma closure a partir de código Java
Como mencionei anteriormente, uma closure é na realidade um objeto: uma instância da classe groovy.lang.Closure.
Sendo assim, em Java poderiamos executar uma closure tal como no exemplo abaixo:
// O código da closure
def soma = {a, b -> a + b}
// O código Java
Closure closure = soma
soma.call({4,3}) // basta passar uma matriz representando os parametros necessários!
Escopo de execução
Veja o código abaixo:
class QualquerClasse {
public void metodoQualquer() {
int x = 10
def closure = {
println "O valor de X é ${x}"
}
closure()
}
}
Como a closure definida em metodoQualquer() sabe da existência da variável x? Devido ao seu escopo. Uma closure possui acesso a todos os atributos definidos no bloco de código em que a mesma é definida.
Paralelamente, o método aonde a closure é definida não possui acesso às suas variáveis internas. O código abaixo por exemplo dispararia uma excessão:
class ClasseFurada {
public void metodoFurado() {
int x = 10;
def closure = {
int y = 1979
println "Não é injusto? Eu vejo ${x}, mas voce não verá minhas variaveis jamais!"}
closure()
print closure.y // ERRO!
}
}