Você está na página 1de 65

Migrando aplicaes do

mundo real para o Java


SE 8
Janario Oliveira | @janarioliver
Michael Nascimento Santos | @mr_ _m
Michel Graciano | @mgraciano
Apresentao
Michael Nascimento Santos
14 anos de experincia com a plataforma Java e programador h 20
anos
Committer do OpenJDK
Membro da organizao do SouJava
JavaOne Rock Star Speaker
Co-lder da JSR-310 (Date & Time API - java.time) e expert em mais 6
JSRs, inclusive a que definiu o Java SE 6
Lder, arquiteto e desenvolvedor na TecSinapse
Janario Oliveira
Mais de 4 anos de experincia com a plataforma Java
Contribuies ativas em projetos opensource como Hibernate, JBoss
AS, NetBeans entre outros
Desenvolvedor na TecSinapse
Apresentao
Michel Graciano
Atualmente Arquiteto de Sistemas na Betha Sistemas e com mais de
10 anos de experincia com a plataforma Java
Membro ativo de projetos open source como o NetBeans e genesis
J fez apresentaes no JavaOne USA e Brasil, bem como em
algumas edies do TDC Floripa e JustJava.
Apresentao
Agenda
Introduo rpida
Migrando aplicaes para Java SE 8
O que podemos migrar automaticamente
Tentando aprofundar o uso dos novos recursos
Dificuldades e perdas de performance
Concluso
Q&A
Disclaimer
Nosso cdigo e testes foram realizados com
o b97(30/06/2013) do Lambda
#java8mundoreal
Introduo rpida
Introduo aos principais conceitos e
tecnologias do Java SE 8
JSR 337: Java SE 8
Datas
2013/09/05 Developer Preview
2014/01/23 Release Candidate
2014/03/18 Final Release
Principais JSRs
294: Improved Modularity Support in the JavaTM Programming
Language (Jigsaw)
308: Annotations on Java Types (no tem API prtica ainda)
310: Date and Time API
335: Lambda Expressions for the JavaTM Programming Language
JSR 310: Date and Time
Spec Leads:
Stephen Colebourne - criador do Joda-Time
Michael Nascimento Santos
Roger Riggs
Baseado e muito semelhante ao Joda-Time, porm melhor
JSR 310: Date and Time
Imutvel e thread-safe
Utilize sempre as classes mais especficas para o problema
YearMonth - Ms e ano
YearMonth.of(2013, Month.JULY);
LocalDate - Data sem hora ou time-zone
LocalDate.now();
LocalDate dataTDC = LocalDate.of(2013, Month.JULY, 12);
LocalTime - Hora sem data ou time-zone
LocalTime meiaNoite = LocalTime.MIDNIGHT;
LocalTime onzeHoras = LocalTime.of(11, 0);
assert meiaNoite.isBefore(onzeHoras);
JSR 310: Date and Time
LocalDateTime - Data com hora sem time-zone
LocalDateTime dataTDCMeioDia = LocalDateTime.of(dataTDC,
LocalTime.NOON);
LocalDateTime dataTDCOnzeHoras = dataTDC.atTime(11, 0);
assert dataTDCMeioDia.minusHours(1).equals(dataTDCOnzeHoras);
OffsetDateTime - Data com hora offset e sem time-zone
OffsetDateTime.of(dataTDCMeioDia, ZoneOffset. ofHours(-3));
ZonedDateTime - Data com hora e time-zone
ZonedDateTime.of(dataTDCMeioDia, ZoneId.of( "America/Sao_Paulo" ));
JSR 310: Date and Time
Outras classes de domnio
Year
Month - enum
DayOfWeek - enum
OffsetDate
OffsetTime
Period
Instant
Duration
Clock
Nova API de formatao
Diversos outros conceitos:
Temporals
Adjusters
Queries
Units
JSR 335:
Lambda Expressions
Permite programao funcional, com maior nvel de reutilizao de cdigo
e escrita concisa
int maiorIdadeDePessoaDoSexoMasculino = -1;
for (Pessoa pessoa : pessoas) {
if (pessoa.getSexo() == Sexo.MASCULINO) {
int idade = pessoa.getIdade();
if (idade > maiorIdadeDePessoaDoSexoMasculino ) {
maiorIdadeDePessoaDoSexoMasculino = idade;
}
}
}
if (maiorIdadeDePessoaDoSexoMasculino != -1) {
trataIdade(maiorIdadeDePessoaDoSexoMasculino );
}
JSR 335:
Lambda Expressions
Permite programao funcional, com maior nvel de reutilizao de cdigo
e escrita concisa
pessoas.stream()
.filter(pessoa -> pessoa.getSexo() == Sexo.MASCULINO)
.mapToInt(Pessoa::getIdade)
.max()
.ifPresent(PessoaProcessor::trataIdade);
JSR 335:
Lambda Expressions
Permite programao funcional, com maior nvel de reutilizao de cdigo
e escrita concisa
pessoas.parallelStream()
.filter(pessoa -> pessoa.getSexo() == Sexo.MASCULINO)
.mapToInt(Pessoa::getIdade)
.max()
.ifPresent(PessoaProcessor::trataIdade);
Migrando aplicaes
para Java SE 8
Migrando aplicaes para
Java SE 8
Foram migradas duas aplicaes:
Um BI customizado para indstria automobilstica com diversos
grficos e relatrios
Uma aplicao 24x7 que ser lanada em breve
Ambas com grande utilizao do Guava, o que facilitou muito a migrao
para utilizao de Lambda Expressions
Guava(code.google.com/p/guava-libraries) - Framework utilitrio com
suporte a programao funcional
Forte utilizao do Joda-Time, em especial o YearMonth por serem
grficos que acumulam dados estatsticos mensais
Iniciamos h 8 meses e muita coisa vem sendo melhorada neste perodo
O que podemos migrar
automaticamente
NetBeans 8 Nightly Builds est em desenvolvimento e j oferece algumas
Hints para o Java SE 8 (Refactor > Inspect and Transform):
Hint: Convert to Lambda
O que podemos migrar
automaticamente
NetBeans 8 Nightly Builds est em desenvolvimento e j oferece algumas
Hints para o Java SE 8 (Refactor > Inspect and Transform):
Hint: Use Functions Operations
O que podemos migrar
automaticamente
Benfica principalmente para projetos Java SE
Usam mais Functional Interfaces (interfaces de um mtodo abstrato
apenas), boas candidatas migrao
Runnable, listeners do Swing etc. so exemplos
Projetos Java EE s se beneficiaro mais se usarem alguma biblioteca
funcional
Ns usamos :-)
Tentando aprofundar o uso
dos novos recursos
Guava nos ajudou na migrao automtica, mas agora precisvamos
eliminar para testar a API
As operaes funcionais mais comuns do Guava tem equivalente quase
direto no Java SE 8:
filter -> filter
transform -> map
limit -> limit
E o resto?
Tentando aprofundar o uso
dos novos recursos
Como converter o resultado de uma operao funcional para uma List?
List<String> names =
brands.stream()
.map(Brand::getName)
.collect(toList());
Atravs de collectors (implementaes padro em Collectors) que
fazemos a maior parte das "terminal operations", i.e., converter de um
stream para outra collection ou classe "sintetizadora" do resultado
Tentando aprofundar o uso
dos novos recursos
Como gerar um Map<Long,Brand>?
//Padro throwingMerger: java.lang.IllegalStateException: Duplicate key
Map<Long,Brand> brandById =
brands.stream()
.collect(toMap(Brand::getId, identity()));
Mas e se houver colises?
Um parmetro adicional, quando especificado, define a estratgia de
"merge":
BinaryOperator<T>
T apply(T u, T v)
(u,v) -> u; //firstWinsMerger () mtodo removido no b97
(u,v) -> v; //lastWinsMerger () mtodo removido no b97
Tentando aprofundar o uso
dos novos recursos
Mas e quando preciso de uma lista com colises?
Map<Holding,List<Brand>> brandByHolding =
brands.stream()
.collect(groupingBy(Brand::getHolding));
Tentando aprofundar o uso
dos novos recursos
Como agregar elementos de uma coleo retornada pelo objeto do
stream?
List<Dealer> branches =
dealers.stream()
.flatMap(dealer -> dealer.getBranches().stream())
.collect(toList());
Tentando aprofundar o uso
dos novos recursos
Novos mtodos teis em Map:
//Java 7
Long l = totalByYearMonth.get(yearMonth);
long total = l == null ? 0L : l;
//Java 8
long total = totalByYearMonth. getOrDefault(yearMonth, 0L);
Tentando aprofundar o uso
dos novos recursos
Novos mtodos teis em Map:
//Java 7
Map<Brand,Long> totalByBrand = totalByBrandByYearMonth.get(yearMonth);
if (totalByBrand == null) {
totalByBrandByYearMonth.put(yearMonth, totalByBrand = new
HashMap<>());
}
Long t = totalByBrand.get(brand);
totalByBrand.put(brand, t == null ? total : t + total);
//Java 8
totalByBrandByYearMonth
.putIfAbsent(yearMonth, new HashMap<>())
.merge(brand, total, Long::sum);
Date and Time
Formatador - por ser thread-safe possvel defini-lo em uma varivel
esttica e utilizar em diversos ponto
public static final DateTimeFormatter ANO_MES_FORMATTER =
DateTimeFormatter. ofPattern("MMM/yyyy", new Locale("pt", "BR"));
Date and Time
A API prover diversos mtodos e formas para que seja efetuado clculos
com data
YearMonth start = YearMonth.now();
YearMonth end = YearMonth.now().plusMonths(1);
int days = ChronoUnit.DAYS.between(start.atDay(1), end.atEndOfMonth())
.getDays();
Date and Time
Mtodos para comparaes
YearMonth yearMonth = YearMonth.of(year, month);
if (yearMonth.isAfter(YearMonth.now())) {
//processa data futura...
}
Date and Time (Hibernate)
Alguns lugares temos a persistncia de LocalDate e LocalDateTime, como
persistir com JPA(Hibernate)? UserType
interface UserType {
boolean isMutable();//no
/** It is not necessary to copy immutable objects */
Object deepCopy (Object value);
/** should perform a deep copy if the type is mutable */
Serializable disassemble (Object value);
/** should perform a deep copy if the type is mutable */
Object assemble (Serializable cached, Object owner );
/** For immutable objects it is safe to simply return the
first parameter */
Object replace (Object original, Object target, Object owner );
}
Date and Time (Hibernate)
Criar duas classes muito parecidas ou uma classe abstrata que
implementa o comportamento parecido das duas? Nenhuma; default
methods
public interface ImmutableUserType extends UserType {
@Override public default boolean equals(Object x, Object y) {
return Objects.equals(x, y);
}
@Override public default int hashCode(Object x) {
return Objects.hashCode(x);
}
@Override public default boolean isMutable() {
return false;
}
...
Date and Time (Hibernate)
E mais mtodos:
...
@Override public default Object deepCopy(Object value) {
return value;
}
@Override public default Serializable disassemble(Object value) {
return (Serializable) value;
}
@Override public default Object assemble(Serializable cached,
Object owner) {
return cached;
}
@Override public default Object replace(Object original,
Object target, Object owner) {
return original;
}
}
LocalDateTimeType
public class LocalDateTimeType implements ImmutableUserType {
@Override public int[] sqlTypes() {
return new int[] { Types.TIMESTAMP}; }
@Override public Class<LocalDateTime> returnedClass() {
return LocalDateTime.class;}
@Override public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner) {
Timestamp persistValue = (Timestamp) rs.getObject(names
[0]);
if (rs.wasNull()) { return null; }
return persistValue.toLocalDateTime();
}
...
Date and Time (Hibernate)
LocalDateTimeType
...
@Override
public void nullSafeSet(PreparedStatement st, Object value,
int index, SessionImplementor session ) {
if (value == null) { st.setNull(index, sqlTypes()[0]);
} else {
Timestamp timestamp = Timestamp
.valueOf((LocalDateTime) value);
st.setObject(index, timestamp, sqlTypes ()[0]);
}
}
}
Date and Time (Hibernate)
Dificuldades
Dificuldades
Dificuldades
Dificuldades
Nossos estressados membros do EG, especialmente nosso amigo Brian,
s vezes do respostas "delicadas"
Porm ele pede desculpas em pvt depois, acreditem ou no :-)
Nem sempre muito fcil achar os mtodos na API e precisa-se do apoio
da lista
Pelo menos eles respondem muito rpido!
Alguns mtodos que mostramos que existem na API hoje foram resultados
dessas discusses
Inclusive o getOrDefault, pro qual o Brian tambm deu uma resposta
delicada de primeira, mas t a agora
A API mudou de forma incompatvel diversas vezes durante esse perodo,
fazendo com que s vezes perdssemos 1 dia inteiro s para deixar tudo
recompilando com lambda de novo :-(
When you're living on the bleeding edge, you should not be surprised
when you do, in fact, bleed
Formatao e estilo
A formatao e estilo do cdigo afeta bastante a legibilidade (mais do que
nunca):
List<String> emailsOrdenados = pessoas.stream().filter((Pessoa pessoa) ->
pessoa.getDataNascimento ().isBefore(dezAnosAtras)).map((Pessoa pessoa)
->
pessoa.getEmail()).sorted((String o1, String o2) -> o1
.compareToIgnoreCase (o2)).collect(Collectors.toList()) ;
Versus:
List<String> emailsOrdenados =
pessoas.stream()
.filter(pessoa -> pessoa.getDataNascimento ().isBefore
(dezAnosAtras))
.map(Pessoa::getEmail)
.sorted(String::compareToIgnoreCase )
.collect(toList());
Suporte a Stream de Maps
Suporte a Stream de Maps
NO TEM!
Suporte a Stream de Maps
Foi discutido pelo EG, mas descartado por exigir classes especficas e ser
melhor suportado com tuplas
Tnhamos na nossa base vrios casos funcionais de Map com Guava e
tivemos que converter para entrySet().stream()
to feio que no daria tempo de vocs entenderem na palestra ( srio!)
Vamos pensar seriamente se vale a pena manter na nossa base de cdigo
com Java SE 8
Stream para array
Como converter?
Stream.toArray(IntFunction<A[]> generator)
Pessoa[] p = pessoas.stream()
//.filter .map ...
.toArray((value) -> {//IntFunction > R apply(int value)
//O que retornar?
//new Pessoa[0] como em List.toArray??
//new Pessoa[10] acho que vai ter 10 ???
//new Pessoa[]{};
//java.lang.IndexOutOfBoundsException: does not fit
});
Stream para array
Como converter?
Stream.toArray(IntFunction<A[]> generator)
Pessoa[] p = pessoas.stream()
//.filter .map ...
.toArray((value) -> {
return new Pessoa[value];
});
Stream para array
Como converter?
Stream.toArray(IntFunction<A[]> generator)
Pessoa[] p = pessoas.stream()
//.filter .map ...
.toArray(Pessoa[]::new); //modo idiomtico
Acessos a recursos Java EE
Algumas APIs Java EE, direta ou indiretamente, acreditam que podem
controlar a instncia "mgica" disponvel via ThreadLocal (ex:
FacesContext.getCurrentInstance())
Com Lambda, elas falham miseravelmente com parallelStream()
Solues?
No usar parallelStream() :-(
Criar na thread principal e sair passando
Fazer patch do seu container preferido (se o seu container vem de
uma empresa de 3 letrinhas, ele todo baseado em threads pra
isso... boa sorte!)
Perturbar o Brian na lista para que haja uma SPI de criao do
mecanismo de execuo de parallelStream() (Michael j cansou de
fazer isso... boa sorte!)
Parar de brincar com tecnologias no suportadas oficialmente :-)
Ns inclumos uma abstrao no meio (porque o Janario t com preguia :
-p)
Problemas - Spring
Spring(ASM) [SPR-10292]
O ASM no conseguia interpretar o bytecode gerado
java.lang.IllegalArgumentException
at org.springframework.asm.ClassReader.<init>(Unknown Source)
Reportado pelo Michael em 13/02/2013
Solucionado 23/04/2013
Ser lanado na verso 4.0 utilizamos em nossos testes a verso
snapshot.
Nestes meses continuamos nossa migrao validando pelos testes de
integrao
Problemas - Spring
Spring - JDK (DocumentBuilderFactory(b92))
No build 92 do JDK exista uma restrio de segurana que no
permitia a requisio, durante a validao, de urls de namespace de
xmls
org.xml.sax.SAXException: schema_reference: Failed to read schema
document 'spring-beans-3.1.xsd', because 'http' access is not allowed.
Solues:
System property -Djavax.xml.accessExternalSchema=all
Chamada via api DocumentBuilderFactory.setAttribute("http://javax.
xml.XMLConstants/property/accessExternalSchema", "all");
No ocorre mais na ltima verso testada b97
Problemas - Spring
Necessrio utilizar o snapshot (enquanto no sair a verso final)
Problemas - JBoss(Jandex)
Jandex (Java Annotation Indexer) JANDEX-14 - Um indexador de
anotaes
No conseguia interpretar classes com bytecode que continham
expresses lambda (invokedynamic constant pool tag 18)
java.lang.IllegalStateException: Unknown tag! pos=1 poolCount = 61
at org.jboss.jandex.Indexer.processConstantPool(Indexer.java:603)
Reportado pelo Janario em 16/05/2013
Pull request aceito 22/05/2013 (https://github.com/wildfly/jandex/pull/12) - Janario Oliveira
Problemas - JBoss x JDK
ConcurrentSkipListSet - Ao adicionar os processors em um o mesmo fica
com chamadas infinitas ao compareTo do objeto adicionado.
org.jboss.as.server.deployment.RegisteredDeploymentUnitProcessor.compareTo(RegisteredDeploymentUnitProcessor.java:41)
org.jboss.as.server.deployment.RegisteredDeploymentUnitProcessor.compareTo(RegisteredDeploymentUnitProcessor.java:28)
java.util.concurrent.ConcurrentSkipListMap.findPredecessor(ConcurrentSkipListMap.java:696)
java.util.concurrent.ConcurrentSkipListMap.doPut(ConcurrentSkipListMap.java:843)
java.util.concurrent.ConcurrentSkipListMap.putIfAbsent(ConcurrentSkipListMap.java:2325)
java.util.concurrent.ConcurrentSkipListSet.add(ConcurrentSkipListSet.java:241)
org.jboss.as.server.DeployerChainAddHandler.addDeploymentProcessor(DeployerChainAddHandler.java:60)
No sabemos se um bug no JDK ou no JBoss
Utilizamos a verso customizada neste ponto em especfico para evitar
este erro.
Problemas - Lombok
Lombok
Issue #145 ainda em aberto desde 15/02/2013 :-(
Processor do Lombok no compatvel com o JavaC do Java SE 8
Incompatvel com NetBeans 7.4, j que o JavaC do Java SE 8
utilizado pelo IDE para os parsings internos (Editor por exemplo)
Reportado 15/02/2013 - Jan Lahoda
Continua em aberto
Apesar de no utilizarmos em nossos projetos, nosso amigo Michel
Graciano utiliza.
Performance
Compilao

Microbenchmark - Caliper
For each - AtomicInteger em uma lista
//ForEachClassic
for (Integer integer : list) {
atomicInteger. accumulateAndGet(integer, Integer::sum);
}
//ForEachStream
list.stream().forEach((integer) -> { ... });
//ForEachArrayList
list.forEach((integer) -> {...});
//ForEachParallelStream
list.parallelStream().forEach((integer) -> {...});
Microbenchmark - Caliper
For each - AtomicInteger
Microbenchmark - Caliper
For each - Fatorial em todos valores de 0 a 2000
private final IntFunction<Integer> factorial = i -> {
return i == 0 ? 1 : i * factorial.apply(i - 1);
};
//ForEachClassic
for (Integer integer : list) {
factorial.apply(integer);
}
//ForEachStream
list.stream().forEach((integer) -> { ... });
//ForEachArrayList
list.forEach((integer) -> { ... });
//ForEachParallelStream
list.parallelStream().forEach((integer) -> { ... });
Microbenchmark - Caliper
For each - Fatorial
Execuo
Concluso
Migrar aplicaes do mundo real para o Java SE 8 hoje possvel - se
voc realmente souber Java e se elas tiverem testes
As novas funcionalidades podem realmente tornar seu cdigo bem mais
legvel
Ganhos de performance podem ser obtidos - mas sempre mea seu
cdigo com ferramentas como Caliper, JMeter e um bom profiler
Vrios mtodos e novos idiomas aceleram o desenvolvimento
O Spring 4.0.0-SNAPSHOT *por enquanto* funciona, ao passo que o
JBoss, s com hacks
Para facilitar a sua migrao use Java 7 (pra comeo de conversa), adote
o Guava e o backport da JSR 310 para Java 7 (https://github.
com/ThreeTen/threetenbp)
Siga as listas e participe ativamente das mesmas
Se voc acha que seria capaz de fazer as coisas descritas nessa palestra
- e gostaria de ter tempo pago pela empresa para isso -, mande seu cv
para recrutamento@tecsinapse.com.br :-)
Obrigado!
Janario Oliveira | @janarioliver
Michael Nascimento Santos | @mr_ _m
Michel Graciano | @mgraciano
Agradecimentos
Michel Graciano (@mgraciano) - Sem dvida
uma grande ajuda na coleta e
organizao do contedo destes slides
Q&A
Janario Oliveira | @janarioliver
Michael Nascimento Santos | @mr_ _m
Michel Graciano | @mgraciano

Você também pode gostar