Um pouco sobre QueryDsl

Alguns links e trechos sobre o framework QueryDSL. (No final do texto, deixei os links onde poderá encontrar os trechos contidos nesse resumo na íntegra e também, dois vídeos apresentando o QueryDSL em diferentes contextos.)

“Querydsl provides a typesafe querying layer on top of JPA, JDO, JDBC and other backends. ”

“Querydsl for SQL provides a typesafe view of the relational schema and makes expressing database queries in Java as intuitive as possible.”

“O Querydsl é compatível com as anotations do JPA. Através de um plugin do maven são criadas classes contendo todos os mapeamentos das suas entidades, uma espécie de sombra da entidade contendo variáveis estáticas. Dessa forma qualquer alteração no mapeamento será refletido nas classes do Querydsl.
Por padrão as classes do Querydsl possuem o mesmo nome das entidades acrescido do prefixo ”Q”. Ex: Entidade “Pessoa” gera “QPessoa”.”

“General usage

Use the the cascading methods of the com.mysema.query.sql.SQLQuery interface like this

from : Define the query sources here.

innerJoin, join, leftJoin, fullJoin, on : Define join elements using these constructs. For the join methods the first argument is the join source and the second the target (alias).

where : Define the query filters, either in varargs form separated via commas or cascaded via the and-operator.

groupBy : Define the group by arguments in varargs form.

having : Define the having filter of the “group by” grouping as an varags array of Predicate expressions.

orderBy : Define the ordering of the result as an varargs array of order expressions. Use asc() and desc() on numeric, string and other comparable expression to access the OrderSpecifier instances.

limit, offset, restrict : Define the paging of the result. Limit for max results, offset for skipping rows and restrict for defining both in one call.”

Alguns exemplos:


List persons = queryFactory.selectFrom(person)
.where(
person.firstName.eq("John"),
person.lastName.eq("Doe"))
.fetch();


List persons = queryFactory.selectFrom(person)
.orderBy(person.lastName.asc(),
person.firstName.desc())
.fetch();

Apresentação do Edson Yanaga sobre QueryDSL:
https://www.infoq.com/br/presentations/sql-facil-no-android
Referências bibliográficas:
http://www.querydsl.com/
http://blog.mysema.com/2011/01/querying-in-sql-with-querydsl.html
http://blog.digithobrasil.com.br/o-poder-do-type-safe/
https://www.youtube.com/watch?v=bLlEgnJCYvo&feature=youtu.be

1) Criando e destruindo objetos – Java efetivo

Assim como os resumos que fiz em relação ao livro de certificação, tenho feito resumo de outros materiais ao qual irei gerando novas postagens e publicando aqui no blog.

O livro Java Efetivo, de Joshua Bloch, também tenho feito resumos.
Neste post irei colocar um resumo do primeiro capítulo do livro “Java Efetivo – segunda edição revisada” da Editora Alta Books.

Obs: É de suma importância a leitura por completo do livro para melhor entendimento do contexto em geral.

1) Considere o uso de métodos de fabricação estáticos em vez de construtores

– Além da forma básica que conhecemos de provermos uma instância da classe através de um construtor público, uma outra técnica interessante, é um método de fabricação estático público.
– Método de fabricação estático não é o mesmo que o padrão Factory Method de Design Patterns.
– Vantagens do uso de métodos de fabricação estáticos:
– Diferente dos construtores, eles têm nomes;
– Métodos de fabricação estáticos não precisam criar um novo objeto sempre que são chamados. (Isso permite que classes imutáveis usem instâncias pré-construídas, ou armazenem em cache as instâncias ao serem construídas). Com isso, há uma melhora grande no desempenho se objetos equivalentes dorem solicitados com frequência.
– Diferente dos construtores, eles podem retornar um objeto de qualquer subtipo de seu tipo de retorno.
– Reduzem a verbosidade na criação de instâncias de tipo parametrizados.
– Desvantagens no uso de métodos de fabricação estáticos:
– Classes sem construtores públicos ou protegidos não pode ter subclasses. (Porém, isso pode ser uma vantagem, já que encoraja os programadores a usarem a composição em vez da herança.)
– Não é possível distinguí-los imediatamente de outros métodos estáticos que sua classe venha a ter.

2) Considere o uso de um objeto criador quando se deparar com muitos parâmetros de construção

– É uma variação do padrão Builder do Design Patterns.
– Em vez de criar o objeto desejado diretamente, o cliente chama um construtor (ou método de fabricação estático) com todos os parâmetros obrigatórios e obtém um objeto criador. Em seguida, o cliente chama métodos tipo setter no objeto criador para configurar cada parâmetro opcional de interesse. Para concluir, o cliente chama o método ‘build’ sem parâmetros para gerar o objeto, que será imutável.

3) Imponha a propriedade Singleton com um construtor privado ou um tipo enum

– Singleton é simplesmente uma classe que é instanciada apenas uma vez.
– Para tornar Serializável um classe Singleton, não basta apenas implementar Serializable. Para preservar a propriedade Singleton (apenas uma instância da classe), terá que declarar todos campos de instância como transientes e fornecer um método readResolve.
– Conforme descrito no livro, “um tipo enum com apenas um elemento é a melhor maneira de implementar um Singleton”

4) Imponha a não-instanciação com um construtor privado

– O uso dessa forma, deve ser utilizadas em classes onde não foram projetadas para serem instanciadas, como é o caso de classes utilitárias.
– Na ausência de construtores, o compilador fornece um construtor padrão. Porém, como dito, algumas classes não servem para ser instanciadas, por isso, devemos então, ter apenas um construtor privado e essa classe torna-se não-instanciável.

5) Evite a criação de objetos desnecessários

– “Geralmente é apropriado reutilizar um objeto individual em vez de criar um novo objeto funcionalmente equivalente sempre que ele é necessário. A reutilização pode ser mais rápida e ao mesmo tempo mais elegante. Um objeto poderá ser sempre reutilizado se for imutável.”

6) Elimine referências de objeto obsoletas

– “A anulação de referências de objeto deve ser a exceção e não a regra.”
– “Sempre que uma classe gerenciar sua própria memória, o programador deve ficar alerta a vazamentos de memória.”
– Um vazamento de memória comum são os listeners e outros retornos de chamadas.

7) Evite finalizadores

– “Os finalizadores são imprevisíveis, com frequência perigosos e geralmente desnecessários.”
– No livro, consta algumas explicações porque não devemos utilizar finalizadores, dentre estes, temos: “há uma grave perda no desempenho”, “nunca devemos depender de um finalizador para atualizar um estado persistente crítico” entre outros. Em resumo, “os finalizadores têm alguns (2 para ser mais específico) usos válidos, mas como regra prátiva, você deve evitá-los”.

Principal referência:
BLOCH, Joshua. Java Efetivo – Segunda edição revisada. Rio de Janeiro: Alta Books Editora, 2008.

Valeu pessoal! =D

Estudo para certificação – Capítulo 10

Esse é a décima e última parte da série de posts que fiz em relação aos temas abordados no livros de certificação Java.
Nesses posts, vou colocando um resumo ou talvez até mesmo trechos na íntegra do livro: Certificação Sun para Programador Java 6 da Kathy Sierra e Bert Bates.

Obs: Caro leitor, você não deve ter como base para uma certificação Java apenas a leituras desses meus resumos em meu blog. É de suma importância a leitura por completo do livro, bem como a realização de alguns simulados.

Capítulo 10 – Desenvolvimento

1) Usando javac e java
– Use -d para modificar o destino de um arquivo de classe quando ele for gerado pelo comando javac.
– A opção -d pode criar, automaticamente, classes de destino dependentes do pacote, caso o diretório-raiz do pacote já exista.
– Use a opção -D em conjunto com o comando java quando quiser definir uma propriedade de sistema.
– As propriedades de sistema constem de pares de nome = valor que devem ser anexados diretamente após -D, por exemplo, -Dmyproperty=myvalue.
– Os argumentos de linha de comando são sempre tratados como String.

2) Procurando com java e javac
– Classpaths padrões podem ser definidos usando-se variáveis de ambiente do SO.
– Pode-se declarar um classpath na linha de comando, e ele substitui o classpath padrão.
– Em um classpath, uma vez encontrada uma classe, a busca é interrompida, de modo que a ordem dos locais de busca é importante.

3) Pacotes e Procura
– Uma instrução import fornece um alias para o nome totalmente qualificado de uma classe.
– Um classpath pode conter tanto caminhos relativos quanto absolutos.

4) Arquivos JAR
– É possível armazenar toda uma estrutura de árvore de diretórios em um mesmo arquivo JAR.
– É possível procurar em arquivos JAR usando-se java e javac.

5)Importações Estáticas
– import static
– Você pode usar importações estáticas para criar atalhos para membros static(variáveis, constantes e métodos) de qualquer classe.


Principal referência:

SIERRA, Kathy; BATES, Bert. Certificação Sun para Programador Java 6 – Guia de estudo – SCJP EXAME 310-065. Rio de Janeiro: Alta Books Editora, 2011.

Links dos demais resumos:
Capítulo 09
Capítulo 08
Capítulo 07
Capítulo 06
Capítulo 05
Capítulo 04
Capítulo 03
Capítulo 02
Capítulo 01

Valeu pessoal!

Estudo para certificação – Capítulo 09

Esse é a nona parte de uma série de posts que irei fazer.
Nesses posts, vou colocando um resumo ou talvez até mesmo trechos na íntegra do livro: Certificação Sun para Programador Java 6 da Kathy Sierra e Bert Bates.

Obs: Caro leitor, você não deve ter como base para uma certificação Java apenas a leituras desses meus resumos em meu blog. É de suma importância a leitura por completo do livro, bem como a realização de alguns simulados.

Capítulo 9 – Threads

1) Criando, instanciando e iniciando novas threads
– As threads podem ser criadas herdando da classe Thread e a sobrescrevendo o método public void run().
– Os objetos das threads também podem ser criados com uma chamada ao construtor de Thread que usa um objeto Runnable como argumento.
– Você pode chamar start() em um objeto Thread somente uma vez.
– É válido criar muitos objetos Thread usando o mesmo objeto Runnable como destino.

2) Transição entre os Estados das Threads
– Uma vez que uma nova thread for iniciada, ela sempre entrará no estado executável.
– Para uma máquina típica, de apenas um processador, só uma thread pode ser executado por vez, embora muitos possam estar no estado executável.
– Uma thread sendo executada pode entrar em um estado bloqueado/de espera por uma chamada wait(), sleep() ou join().

3) Sleep, Yield e Join
– A suspensão é usada para retardas a execução por um período de tempo e nenhum bloqueio será liberado quando um thread entrar em suspensão.
– O método setPriority() é usado em objetos Thread para às threads um nível de prioridade entre 1(baixo) e 10(alto), embora não sejam garantidas.
– O método yeld() pode fazer com que uma thread em execução seja interrompida se houver threads executáveis com a mesma prioridade.
– Quando uma thread chamar o método join() de outra thread, aquela que estiver sendo executada esperará até que a thread ao qual foi adicionada seja concluída.

5) Problemas de Acesso Simultâneo e Threads Sincronizados
– Os métodos synchronizes impedem que mais de uma thread acesse o código de um métidi crítico do objetos simultâneo.
– Embora só uma thread possa acessar o código sincronizado de uma instância específica, várias threads podem acessar o mesmo código não sincronizado do objeto.
– Quando um objeto entra em suspensão, seus bloqueios estarão indisponíveis para outras threads.

6) Comunicando-se com os Objetos Através da Espera(wait()) e Notificação(notify())
– O método wait() permite que uma thread diga:”Não há nada que eu possar fazer aqui, portanto, coloque-me em seu pool de espera e me avise quando acontecer algo que me interesse”.
– O método notify() é usado para enviar um sinal a somente uma das threads que estiverem aguardando no pool de espera desse mesmo objeto.
– O método notify() não pode especificar qual thread em espera deverá ser notificada.
– O método notifyAll() funciona da mesma maneira que notify(), só que envia o sinal para todas as threads que estiverem aguardando no objeto.
– Todos os 3 métodos devem ser chamados de dentro de um contexto sincronizado.

7) Threads em Impasse
– O impasse ocorre quando a execução da thread é interrompida porque o código está esperando que os bloqueios sejam removidos dos objetos.
– Em outras palavras, duas threads estão esperando a liberação do bloqueio um do outro, ou seja, os bloqueios nunca serão liberados!


Principal referência:

SIERRA, Kathy; BATES, Bert. Certificação Sun para Programador Java 6 – Guia de estudo – SCJP EXAME 310-065. Rio de Janeiro: Alta Books Editora, 2011.

Não deixem de verificar os próximos capítulos.
Valeu pessoal!

Estudo para certificação – Capítulo 08

Essa é a oitava parte de uma série de posts que irei fazer.
Nesses posts, vou colocando um resumo ou talvez até mesmo trechos na íntegra do livro: Certificação Sun para Programador Java 6 da Kathy Sierra e Bert Bates.

Obs: Caro leitor, você não deve ter como base para uma certificação Java apenas a leituras desses meus resumos em meu blog. É de suma importância a leitura por completo do livro, bem como a realização de alguns simulados.

Capítulo 8 – Classes Internas

1) Classes Internas.
– A classe interna é um membro individual da classe encapsuladora(externa), portando, pode ser marcada com um modificador de acesso, assim como com o modificador abstract e final.
– Para instanciar uma classe interna, você precisa ter uma referência à instância da classe externa.

2) Classes Internas Locais de Método
– Para a classe interna ser usada, você precisa instanciá-la, e essa instanciação deve ocorrer dentro do mesmo método, porém, após o código de definição da classe.
– Uma classe interna local de método não pode usar variáveis declaradas dentro do mesmo método, a menos que essas variáveis sejam marcadas como final.

3) Classes Internas Anônimas
– As classes internas anônimas não têm nome, e seu tipo deve ser uma subclasse do tipo nomeado ou um implementador da interface nomeada.
– A classe interna anônima pode estender uma subclasse ou implementar uma interface. Diferente das classes não-anônimas(internas ou não), uma classe interna anônima não pode fazer as duas coisas. Em outras palavras, não pode estender uma classe e implementar uma interface, nem implementar mais de uma interface.

4) Classes Aninhadas Estáticas
– Tecnicamente, uma classe aninhada estática não é uma classe interna, mas, em vez disso, é considerada uma classe aninhada de nível superior.
– Você não precisa de uma instância da classe externa para instanciar uma classe aninhada estática.
– Instanciar uma classe aninhada estática requer o uso tanto do nome da classe extrena quanto o da aninhada, como por exemplo:
BigOuter.Nested n = new BigOuter.Nested();


Principal referência:

SIERRA, Kathy; BATES, Bert. Certificação Sun para Programador Java 6 – Guia de estudo – SCJP EXAME 310-065. Rio de Janeiro: Alta Books Editora, 2011.

Não deixem de verificar os próximos capítulos.
Valeu pessoal!

Estudo para certificação – Capítulo 07

Esse é a sétima parte de uma série de posts que irei fazer.
Nesses posts, vou colocando um resumo ou talvez até mesmo trechos na íntegra do livro: Certificação Sun para Programador Java 6 da Kathy Sierra e Bert Bates.

Obs: Caro leitor, você não deve ter como base para uma certificação Java apenas a leituras desses meus resumos em meu blog. É de suma importância a leitura por completo do livro, bem como a realização de alguns simulados.

Capítulo 7 – Genéricos e Coleções.

1) Sobrescrevendo hashCode() e equals().
– equals(),hashCode() e toString() são public.
– Use == para determinar se duas variáveis de referência apontam para o mesmo objeto.
– Use equals() para determinar se dois objetos são significativamente equivalentes.
– Se você não sobrescrever equals(), dois objetos diferentes não poderão ser considerado iguais.
– Quando sobrescrever equals(),use o operador instanceof para se certificar de que está avaliando uma classe apropriada.
– Quando sobrescrever equals(),compare os atributos significativos dos objetos.
– Se x.equals(y) for verdadeiro, x.hashCode() == y.hashCode() deve ser verdadeiro.
– As variáveis transient não são apropriadas para equals() e hashCode().

2) Coleções
– List de itens: Ordenada, repetição permitida, com um índice.
– Set de itens: Podem ou não ser ordenados e/ou classificados e a repetição não é permitida.
– Map de itens com chaves: Podem ou não ser ordenados e/ou classificados e a repetição de chave não é permitida.
– Queue de itens a serem processados: Ordenados por FIFO(First-in First-out) ou por prioridade.

3) Atributos Principais das Classes Comuns de Coleção
– ArrayList: iteração e acesso aleatório rápidos.
– Vector: Como um ArrayList um pouco mais lento, devido a seus métodos sincronizados.
– LinkedList: Adequado para a inserção de elementos ao final, ou seja, para pilhas e fila.
– HashSet: Assegura a não existência de duplicatas, não fornece ordenação.
– LinkedHashSet: Sem duplicatas, itera na ordem de inserção.
– TreeSet: Sem duplicatas, itera na ordem de classificação.
– HashMap: Atualizações mais rápidas(pares chave/valor), permite uma chave null e muitos valores null.
– HashTable: Com um HashMapmais lento(métodos sincronizados. Nenhum valor ou chave null é permitido.
– LinkedHashMap: Iterações mais rápidas, itera por ordem de inserção ou último item acessado. Permite uma chave null e muitos valores null.
– TreeMap: Um mapa classificado.
– PriorityQueue: Uma lista de objetos ordenada pela prioridade dos elementos.

4) Usando Classes de Coleção
– As coleções só podem armazenar
– Faça iterações com loop for aprimorado, ou com um Iterator via hasNext() e next().
– hasNext() determina se existem mais elementos, o Iterator não se move.
– next() retorna o elemento seguinte e move o Iterator adiante.
– Para funcionarem corretamente, as chaves de um Map devem sobrescrever equals() e hashCode().
– As filas usam offer() para adicionar um elemento, poll() para remover o primeiro item da fila, e peek() para ver o primeiro item da fila.
– A partir do Java 6, TreeSets e TreeMaps têm novos métodos de navegação como floor() e highter().
– É possível criar/estender sub-cópias ‘vinculadas’ de TreeSets e TreeMaps.

5) Classificando e Pesquisando em Arrays e Listas
– A classificação pode ser feita na ordem natural, ou através de um Comparable ou de vários Comparators.
– Implemente Comparable usando compareTo().
– Crie vários Comparators para classificar uma classe de várias formas, implemente compare().

6)Classes Utilitárias: Collections e Arrays
– Ambas fornecem um método sort(). Classifica usando um Comparator ou usando a ordem natural.
– Ambas fornecem um método binarySearch(). Busca em um array ou List pré-classificado.

7) Genéricos
– Os genéricos lhe permitem forçar a segurança de tipos, em tempo de compilação(typesafe), para conjuntos(ou outras classes e métodos declarados usando-se parâmetros de tipos genéricos).
– Um ArrayList pode aceitar referências do tipo Dog, Cat ou qualquer outro subtipo de Animal(subclasse ou, se Animal for uma interface).
– Ao usar coleção genéricos, não é necessária uma conversão(cast) para se obter elementos(de tipo declarado) a partir da coleção.
– Lembre-se de que ‘compila sem erros’ não é o mesmo que ‘compila sem avisos’. No exame, um aviso de compilação não é considerado como erro ou falha de compilação.
– As atribuições polimórficas aplicam-se somente ao tipo-base, e não ao parâmetro de tipo genérico.
Você pode usar
List aList = new ArrayList();
Mas não
List aList = new ArrayList();
– A sintaxe dos coringas permite que um método genérico aceite subtipos(ou supertipos) do tipo declarado no argumento do método.
void addDog(List<? extends Dog) {} // Pode usar Dog ou Beagle.
– A palavra-chave extends, na condição coringa é usada para significar ou 'estende' ou 'implementa'. Assim, Dog pode ser uma classe ou uma interface.
– Ao se usar coringa, o conjunto pode ser acessado, mas não modificado.
– List refere-se apenas a um List, enquanto que List podem armazenar qualquer tipo de objeto, mas apenas para acesso.
– As convenções de declaração para genéricos usam T para tipo e E para o elemento, em relação a coringas.
– O identificador de tipo dos genéricos pode ser usado em declarações de classes, métodos e variáveis.
– Você pode declarar um método genérico usando um tipo não definido na classe:
public T void makeList(T t) {}
não está usando T como o tipo de retorno. Esse método tem um tipo de retorno void, mas para usar T dentro do argumento do método você deve declarar o , o que acontece antes do tipo de retorno.


Principal referência:

SIERRA, Kathy; BATES, Bert. Certificação Sun para Programador Java 6 – Guia de estudo – SCJP EXAME 310-065. Rio de Janeiro: Alta Books Editora, 2011.

Não deixem de verificar os próximos capítulos.
Valeu pessoal!

Estudo para certificação – Capítulo 06

Esse é a sexta parte de uma série de posts que irei fazer.
Nesses posts, vou colocando um resumo ou talvez até mesmo trechos na íntegra do livro: Certificação Sun para Programador Java 6 da Kathy Sierra e Bert Bates.

Obs: Caro leitor, você não deve ter como base para uma certificação Java apenas a leituras desses meus resumos em meu blog. É de suma importância a leitura por completo do livro, bem como a realização de alguns simulados.

Capítulo 6 – String, E/S, Formatação e Parsing.

1) Usando String, StringBuffer e StringBuilder.
– Os objetos String são imutáveis, porém, as variáveis de referência String não.
– A classe String é final – seus métodos não podem ser sobrescritos.
– As Strings têm um método chamado length() e os arrays têm um atributo chamado length.
– A API de StringBuffer é a mesma que a API de StringBuilder, exceto pelo fato de que os métodos de StringBuilder não são sincronizados para segurança de threads(thread-safe).
– Os métodos de StringBuilder deverão rodar mais rápido do que os de StringBuffer.
– Métodos String que você deve memorizar: charAt(), toString(), concat(), equalsIgnoreCase(), length(), replace(), substring(), toLowerCase(), toUpperCase() e trim().
– Métodos de StringBuffer/StringBuilder que você deve memorizar: append(), delete(), insert(), reserve() e toString().

2) E/S de Arquivos
– As classes do pacote java.io que você precisa entender são: File, FileReader, BufferedReader, FileWriter, BufferedWriter e PrintWriter.
– Objetos File podem representar um arquivo ou um diretório.
– A classe File lhe permite gerenciar arquivos e diretórios.
– FileWriter e FileReader são classes de E/S de baixo nível. Você pode usá-las para escrever em arquivos e lê-los, mas normalmente elas devem ser encapsuladas.
– É bastante comum ‘encapsular’ um BufferedWriter em um FileWriter, para se ter acesso a métodos de nível mais alto.
– Objetos console podem ler entradas que não são exibidas na tela e são instanciados usando System.console().

3) Serialização
– Antes que os objetos de uma classes possam ser serializados, deve-se implementar a interface Seiralizable.
– O método ObjectOutPutStream.writeObject() serializa objetos, enquanto que o método ObjectInputStream.readObject() desserializa objetos.
– Se uma variável de instância for marcada como transient, ela não será serializada.

4) Datas, Números e Moeda
– As classes que você precisa entender são java.util.Date, java.util.Calendar, java.text.DateFormat, java.text.NumberFormat e java.util.Locale.
– Os métodos de Calendar que você deverá entender são add(), que lhe permite adicionar ou subtrair várias partes(minutos, dias, anos e assim por diante) de datas, e roll(), que funciona como add(), mas não incrementa as partes maiores de uma data(por exemplo: adicionar 10 meses a uma data de outubro modifica o mês para agosto, mas não incrementa o valor do ano do Calendar).
– O método DateFormat.format() é usado para se criar Strings contendo datas devidamente formatadas.
– Para o examete, você deverá entender o processo de criação de Locales usando-se idiomas ou uma combinação de idiomar e país.

5) Parsing, Tokenização e Formatação
– regex é uma abreviação de expressões regulares, que são padrões usados para se procurar por dados dentro de grandes origens de dados.
– regex é uma sublinguagem existente em Java e em outras linguagens.
– Estude os metacaracteres \d, \s, \w e .(ponto).
– regex fornece quantificadores que lhe permitem especificar conceitos como: “Procure por um ou mais dígitos em sequência”.
– Estude os quantificadores ?, * e +.
– As classes Pattern e Matcher têm as capacidades regex mais poderosas em Java.
– Você deverá entender o método compile() de Pattern e os métodos matcher(), pattern(), find(), start() e group() de Matcher.
– A tokenização é o processo de se dividir dados em pequenos pedaços delimitados.
– A tokenização pode ser feita com a classe Scanner ou com String.split().
– A classe Scanner lhe permite tokenizar strings, streams ou arquivos.
– Existem dois métodos novos em Java para formatação de dados. Esses métodos são format() e printf(). Eles se encontram na classe PrintStream, da qual o out de System.out é uma instância.


Principal referência:

SIERRA, Kathy; BATES, Bert. Certificação Sun para Programador Java 6 – Guia de estudo – SCJP EXAME 310-065. Rio de Janeiro: Alta Books Editora, 2011.

Não deixem de verificar os próximos capítulos.
Valeu pessoal!