<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: FUNDAMENTOS JAVA</title>
    <description>The latest articles on DEV Community by FUNDAMENTOS JAVA (@fundamentosjava).</description>
    <link>https://dev.to/fundamentosjava</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1604957%2Fc442ad94-bd38-4a71-a18c-c20f90e38cab.png</url>
      <title>DEV Community: FUNDAMENTOS JAVA</title>
      <link>https://dev.to/fundamentosjava</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fundamentosjava"/>
    <language>en</language>
    <item>
      <title>12.5 Reflection: parameter names</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 03 May 2025 03:02:57 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/125-reflection-parameter-names-14ho</link>
      <guid>https://dev.to/fundamentosjava/125-reflection-parameter-names-14ho</guid>
      <description>&lt;p&gt;Nova funcionalidade: Agora é possível recuperar os nomes dos parâmetros de métodos e construtores usando reflection.&lt;/p&gt;

&lt;p&gt;Como fazer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use o método getConstructor(...) para obter o construtor desejado.&lt;/li&gt;
&lt;li&gt;Em seguida, chame getParameters() para obter um array de Parameter.&lt;/li&gt;
&lt;li&gt;Use getName() para acessar o nome de cada parâmetro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Importante!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Por padrão, os nomes exibidos serão genéricos (arg0, arg1).&lt;/li&gt;
&lt;li&gt;Para ver os nomes reais, é necessário compilar o código com a flag:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-parameters

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemplo com flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javac -parameters Usuario.java

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem essa flag:&lt;br&gt;
isNamePresent() retornará false.&lt;br&gt;
Os nomes continuarão como arg0, arg1, etc.&lt;/p&gt;

&lt;p&gt;Antes do Java 8:&lt;br&gt;
Era possível recuperar nomes com -g (debug), mas exigia manipulação de bytecode.&lt;/p&gt;

&lt;p&gt;Dependia de bibliotecas externas, como o Paranamer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Paranamer paranamer = new CachingParanamer();
String[] parameterNames = paranamer.lookupParameterNames(constructor);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vantagens da nova abordagem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evita dependências externas.&lt;/li&gt;
&lt;li&gt;Facilita o uso de reflection de forma mais limpa e segura.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛠️ Como compilar com a flag -parameters:&lt;br&gt;
No terminal, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javac -parameters Usuario.java ReflectionTeste.java

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E depois execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;java ReflectionTeste

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🧾 Saída esperada (com -parameters):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;true: nome
true: pontos

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔁 Saída sem a flag -parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;false: arg0
false: arg1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 Importante: Para que os nomes reais dos parâmetros apareçam (nome, pontos), compile com a flag -parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkrz2lb6cx0gndjswnxu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkrz2lb6cx0gndjswnxu.jpg" alt="Image description" width="800" height="482"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Rodar REBUILD PROJECT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ReflectionComParametro.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>12.4 Fim da Permgen</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 03 May 2025 02:24:18 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/124-fim-da-permgen-2ic2</link>
      <guid>https://dev.to/fundamentosjava/124-fim-da-permgen-2ic2</guid>
      <description>&lt;p&gt;O que mudou: A PermGen, uma área da memória da JVM usada para armazenar metadados de classes, foi removida a partir do Java 8.&lt;/p&gt;

&lt;p&gt;Impacto: Não ocorrerá mais o erro clássico:&lt;br&gt;
java.lang.OutOfMemoryError: PermGen.&lt;/p&gt;

&lt;p&gt;Substituição: Agora é usada a Metaspace, uma área de memória nativa (fora do heap da JVM) para armazenar os metadados das classes.&lt;/p&gt;

&lt;p&gt;Inspiração: Solução similar já era usada em JVMs como o JRockit da Oracle e na JVM da IBM.&lt;/p&gt;

&lt;p&gt;Referência oficial (JEP 122):&lt;br&gt;
Removendo a PermGen - JEP 122&lt;/p&gt;

&lt;p&gt;Mais detalhes sobre performance e migração:&lt;br&gt;
Java 8 – PermGen vs Metaspace (artigo na DZone)&lt;/p&gt;

&lt;p&gt;Antes:&lt;br&gt;
-XX:PermSize e -XX:MaxPermSize.&lt;/p&gt;

&lt;p&gt;⚠️ Novos parâmetros:&lt;br&gt;
-XX:MetaspaceSize (tamanho inicial).&lt;br&gt;
-XX:MaxMetaspaceSize (limite máximo, se definido).&lt;/p&gt;

&lt;p&gt;Onde alterar:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrsgd7l8u848jwnmydzz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrsgd7l8u848jwnmydzz.jpg" alt="Image description" width="652" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Memory Indicator&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62x9o6vqvqpey2s58ap7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62x9o6vqvqpey2s58ap7.jpg" alt="Image description" width="534" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>performance</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Anotações Repetidas (Repeating Annotations)</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Tue, 29 Apr 2025 22:00:01 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/anotacoes-repetidas-repeating-annotations-3gg1</link>
      <guid>https://dev.to/fundamentosjava/anotacoes-repetidas-repeating-annotations-3gg1</guid>
      <description>&lt;p&gt;1 Problema antes do Java 8&lt;br&gt;
Não era possível declarar a mesma anotação várias vezes.&lt;/p&gt;

&lt;p&gt;Tentativa gerava erro: Duplicate annotation.&lt;/p&gt;

&lt;p&gt;2 Solução: @Repeatable&lt;br&gt;
Agora é possível usar anotações múltiplas em um mesmo elemento.&lt;/p&gt;

&lt;p&gt;Definindo a anotação repetível:&lt;br&gt;
Usar @Repeatable apontando para um "container" (ex.: @Roles):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@Repeatable(Roles.class)&lt;br&gt;
@Documented&lt;br&gt;
@Retention(RetentionPolicy.RUNTIME)&lt;br&gt;
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})&lt;br&gt;
public @interface Role {&lt;br&gt;
    String value();&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Container de anotações:&lt;br&gt;
&lt;code&gt;@Documented&lt;br&gt;
@Retention(RetentionPolicy.RUNTIME)&lt;br&gt;
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})&lt;br&gt;
public @interface Roles {&lt;br&gt;
    Role[] value();&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Aplicação prática:&lt;br&gt;
&lt;code&gt;@Role("presidente")&lt;br&gt;
@Role("diretor")&lt;br&gt;
public class RelatorioController { }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3 Recuperando anotações com Reflection&lt;br&gt;
Método getAnnotationsByType facilita acesso:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RelatorioController controller = new RelatorioController();&lt;br&gt;
Role[] annotationsByType = controller.getClass().getAnnotationsByType(Role.class);&lt;br&gt;
Arrays.asList(annotationsByType)&lt;br&gt;
      .forEach(a -&amp;gt; System.out.println(a.value()));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Exemplo: ExemploAnotacoesRepetidas.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Limitações da inferência no lambda</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Tue, 29 Apr 2025 21:59:51 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/limitacoes-da-inferencia-no-lambda-nc3</link>
      <guid>https://dev.to/fundamentosjava/limitacoes-da-inferencia-no-lambda-nc3</guid>
      <description>&lt;p&gt;1 Problemas de inferência com lambdas encadeados&lt;br&gt;
Method reference funciona sem problemas:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.comparingInt(Usuario::getPontos)&lt;br&gt;
    .thenComparing(Usuario::getNome));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lambda equivalente pode não compilar:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.comparingInt(u -&amp;gt; u.getPontos())&lt;br&gt;
    .thenComparing(u -&amp;gt; u.getNome())); // Não compila&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2 Soluções para compilar lambdas encadeados&lt;/p&gt;

&lt;p&gt;Explicitando o tipo no lambda:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.comparingInt((Usuario u) -&amp;gt; u.getPontos())&lt;br&gt;
    .thenComparing(u -&amp;gt; u.getNome()));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Quebrando o encadeamento:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Comparator&amp;lt;Usuario&amp;gt; comparator = Comparator.comparing(u -&amp;gt; u.getPontos());&lt;br&gt;
usuarios.sort(comparator.thenComparing(u -&amp;gt; u.getNome()));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Forçando tipo genérico do método:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.&amp;lt;Usuario&amp;gt;comparingInt(u -&amp;gt; u.getPontos())&lt;br&gt;
    .thenComparing(u -&amp;gt; u.getNome()));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3 Preferência por method reference&lt;br&gt;
Method reference (Usuario::getPontos) facilita a inferência dos tipos.&lt;/p&gt;

&lt;p&gt;Usado principalmente em interfaces fluentes como Comparator.reversed().&lt;/p&gt;

&lt;p&gt;Exemplo: método reversed()&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.comparingInt(Usuario::getPontos).reversed());&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lambda precisa de tipo explícito:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;usuarios.sort(Comparator.comparingInt((Usuario u) -&amp;gt; u.getPontos()).reversed());&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Exemplo: ExemploInferenciaEncadeamento.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Qual é o tipo de uma expressão Lambda?</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Tue, 29 Apr 2025 21:59:36 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/qual-e-o-tipo-de-uma-expressao-lambda-o30</link>
      <guid>https://dev.to/fundamentosjava/qual-e-o-tipo-de-uma-expressao-lambda-o30</guid>
      <description>&lt;p&gt;1 Lambda precisa ter um tipo funcional&lt;br&gt;
Lambdas não podem ser atribuídas a tipos que não são interfaces funcionais, como Object.&lt;/p&gt;

&lt;p&gt;Exemplo que não compila:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Object o = () -&amp;gt; {&lt;br&gt;
    System.out.println("eu sou um runnable!");&lt;br&gt;
};&lt;br&gt;
new Thread(o).start(); // Erro&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2 Lambda atribuída corretamente a uma interface funcional&lt;br&gt;
Atribuindo explicitamente para Runnable:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Runnable r = () -&amp;gt; {&lt;br&gt;
    System.out.println("eu sou um runnable!");&lt;br&gt;
};&lt;br&gt;
new Thread(r).start(); // Correto&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3 Lambda passada diretamente como argumento&lt;br&gt;
Quando passamos diretamente no construtor, o compilador usa o contexto para inferir o tipo:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;new Thread(() -&amp;gt; {&lt;br&gt;
    System.out.println("eu sou um runnable?");&lt;br&gt;
}).start();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;O construtor Thread(Runnable r) espera um Runnable, então o compilador infere que a lambda é Runnable.&lt;/p&gt;

&lt;p&gt;4 Target Type&lt;/p&gt;

&lt;p&gt;O tipo esperado pelo compilador baseado no contexto é chamado de Target Type.&lt;/p&gt;

&lt;p&gt;O Target Type permite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Inferir o tipo da expressão lambda;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reconhecer que uma mesma lambda pode representar diferentes interfaces funcionais.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo com mesma expressão lambda e diferentes tipos:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Callable&amp;lt;String&amp;gt; c = () -&amp;gt; "retorna uma String";&lt;br&gt;
PrivilegedAction&amp;lt;String&amp;gt; p = () -&amp;gt; "retorna uma String";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Na primeira linha: Callable.&lt;br&gt;
Na segunda linha: PrivilegedAction.&lt;br&gt;
O Target Type define o significado.&lt;/p&gt;

&lt;p&gt;5 O mesmo acontece com Method Reference&lt;/p&gt;

&lt;p&gt;A method reference também usa Target Type para inferência.&lt;/p&gt;

&lt;p&gt;Exemplo com method reference&lt;br&gt;
&lt;code&gt;Callable&amp;lt;String&amp;gt; c = callable::call;&lt;br&gt;
PrivilegedAction&amp;lt;String&amp;gt; action = callable::call;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A mesma referência callable::call pode se adaptar a diferentes interfaces.&lt;/p&gt;

&lt;p&gt;6 Diferença entre Lambda e Method Reference&lt;br&gt;
Method references tornam a inferência mais forte, porque o tipo está mais explícito.&lt;/p&gt;

&lt;p&gt;Além disso, é permitida a conversão entre interfaces funcionais compatíveis.&lt;/p&gt;

&lt;p&gt;Exemplo: ExemploTargetType.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Conversões entre interfaces funcionais</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Tue, 29 Apr 2025 21:59:30 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/conversoes-entre-interfaces-funcionais-4lmg</link>
      <guid>https://dev.to/fundamentosjava/conversoes-entre-interfaces-funcionais-4lmg</guid>
      <description>&lt;p&gt;1 Não existe conversão automática entre interfaces funcionais equivalentes&lt;br&gt;
Mesmo que duas interfaces sejam "equivalentes" (ex.: Supplier e PrivilegedAction), o compilador não faz a conversão automaticamente.&lt;/p&gt;

&lt;p&gt;2 Exemplo de método que recebe um Supplier&lt;br&gt;
&lt;code&gt;private void execute(Supplier&amp;lt;String&amp;gt; supplier) {&lt;br&gt;
    System.out.println(supplier.get());&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Uso correto com Supplier:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Supplier&amp;lt;String&amp;gt; supplier = () -&amp;gt; "executando um supplier";&lt;br&gt;
execute(supplier);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3 Tentativa incorreta usando PrivilegedAction&lt;br&gt;
Erro: o compilador não permite passar PrivilegedAction diretamente.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PrivilegedAction&amp;lt;String&amp;gt; action = () -&amp;gt; "executando uma ação";&lt;br&gt;
execute(action); // Não compila&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Motivo: O método execute(Supplier) não aceita diretamente um PrivilegedAction.&lt;/p&gt;

&lt;p&gt;4 Como converter usando Method Reference&lt;br&gt;
Usamos uma referência de método (action::run) para indicar a adaptação explicitamente.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PrivilegedAction&amp;lt;String&amp;gt; action = () -&amp;gt; "executando uma ação";&lt;br&gt;
execute(action::run);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Exemplo: ExemploInferenciaTipos.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Situações de Ambiguidade com Expressões Lambda</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 26 Apr 2025 18:01:55 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/situacoes-de-ambiguidade-com-expressoes-lambda-4526</link>
      <guid>https://dev.to/fundamentosjava/situacoes-de-ambiguidade-com-expressoes-lambda-4526</guid>
      <description>&lt;p&gt;Tópicos Principais:&lt;br&gt;
Inferência de Tipos em Lambdas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 8 pode inferir o tipo de uma expressão lambda baseado no contexto&lt;/li&gt;
&lt;li&gt;Funciona bem quando há apenas uma interface funcional compatível&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Casos de Ambiguidade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ocorrem quando múltiplas interfaces funcionais têm a mesma assinatura&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplo entre Supplier e PrivilegedAction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ambos têm um único método abstrato sem parâmetros que retorna T&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problema com Sobrecarga de Métodos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quando existem métodos sobrecarregados com diferentes interfaces funcionais compatíveis&lt;/li&gt;
&lt;li&gt;O compilador não consegue determinar qual método usar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solução para Ambiguidade:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uso de casting explícito para especificar o tipo da lambda&lt;/li&gt;
&lt;li&gt;Alternativa: usar referência de método quando possível&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ver: AmbiguidadeLambda.java&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Cap 12 Apêndice: mais Java 8 com reflection, JVM, APIs e limitações</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 26 Apr 2025 17:46:50 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/cap-12-apendice-mais-java-8-com-reflection-jvm-apis-e-limitacoes-4b5d</link>
      <guid>https://dev.to/fundamentosjava/cap-12-apendice-mais-java-8-com-reflection-jvm-apis-e-limitacoes-4b5d</guid>
      <description>&lt;p&gt;&lt;strong&gt;12.1: Novos Detalhes na Linguagem (Operador Diamante Melhorado)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tópicos Principais:&lt;br&gt;
&lt;strong&gt;Operador Diamante (&amp;lt;&amp;gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Introduzido no Java 7 para reduzir código redundante&lt;/li&gt;
&lt;li&gt;Permite substituir new ArrayList() por new ArrayList&amp;lt;&amp;gt;()&lt;/li&gt;
&lt;li&gt;Limitação original: só funcionava na declaração de variáveis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Melhorias no Java 8:&lt;/strong&gt;&lt;br&gt;
Inferência de tipos ampliada para contextos adicionais&lt;br&gt;
Agora funciona em:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chamadas de métodos&lt;/li&gt;
&lt;li&gt;Retornos de métodos&lt;/li&gt;
&lt;li&gt;Argumentos de métodos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Casos de Uso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repositorio.adiciona(new ArrayList&amp;lt;&amp;gt;()) - agora funciona&lt;/li&gt;
&lt;li&gt;repositorio.adiciona(Collections.emptyList()) - também funciona&lt;/li&gt;
&lt;li&gt;Não precisa mais de anotações explícitas de tipo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Comparação Java 7 vs Java 8:&lt;/strong&gt;&lt;br&gt;
Java 7 exigia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repositorio.adiciona(new ArrayList&amp;lt;Usuario&amp;gt;());
repositorio.adiciona(Collections.&amp;lt;Usuario&amp;gt;emptyList());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Java 8 aceita:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repositorio.adiciona(new ArrayList&amp;lt;&amp;gt;());
repositorio.adiciona(Collections.emptyList());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;JEP Relacionado:&lt;/strong&gt;&lt;br&gt;
JEP 101: Generalized Target-Type Inference&lt;br&gt;
Link: &lt;a href="http://openjdk.java.net/jeps/101" rel="noopener noreferrer"&gt;http://openjdk.java.net/jeps/101&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ver OperadorDiamanteExemplo.java&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>11.9 Sistema de assinaturas</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 19 Apr 2025 04:42:26 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/119-sistema-de-assinaturas-3fi7</link>
      <guid>https://dev.to/fundamentosjava/119-sistema-de-assinaturas-3fi7</guid>
      <description>&lt;p&gt;📘 Resumo do Sistema de Assinaturas (Capítulo 11.9)&lt;br&gt;
Esse tópico mostra como modelar um sistema de assinaturas mensais usando Java 8, representando o tempo de vigência da assinatura e o cálculo do valor total pago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modelagem da classe Subscription:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utiliza Optional para a data de término, tornando explícito o tratamento de assinaturas ativas/encerradas&lt;/li&gt;
&lt;li&gt;Dois construtores: um para assinaturas ativas (sem data de término) e outro para assinaturas encerradas&lt;/li&gt;
&lt;li&gt;Método getTotalPaid() que calcula automaticamente o valor total pago&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cálculo de duração:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uso de ChronoUnit.MONTHS.between() para calcular meses entre datas&lt;/li&gt;
&lt;li&gt;Utilização inteligente de Optional.orElse() para tratar assinaturas ativas (usando data atual)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Operações com streams:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cálculo do total pago por todas as assinaturas com map e reduce&lt;/li&gt;
&lt;li&gt;Filtragem de assinaturas ativas com filter(sub -&amp;gt; sub.getEnd().isEmpty())&lt;/li&gt;
&lt;li&gt;Cálculo de estatísticas como valor médio por assinatura&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Vantagens do design:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Código limpo sem verificações de null&lt;/li&gt;
&lt;li&gt;Lógica de negócio encapsulada na classe Subscription&lt;/li&gt;
&lt;li&gt;Flexibilidade para diferentes tipos de consultas e relatórios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exemplos práticos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cálculo individual por assinatura&lt;/li&gt;
&lt;li&gt;Agregação de valores totais&lt;/li&gt;
&lt;li&gt;Filtros e estatísticas sobre a coleção de assinaturas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta implementação demonstra como usar recursos modernos do Java (Optional, Streams, Date/Time API) para modelar um sistema de assinaturas de forma elegante e eficiente.&lt;/p&gt;

&lt;p&gt;Ver exemplo: SubscriptionSystem.java&lt;/p&gt;

</description>
      <category>java</category>
      <category>systemdesign</category>
      <category>programming</category>
    </item>
    <item>
      <title>11.8 Relatórios com datas</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 19 Apr 2025 04:23:43 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/118-relatorios-com-datas-4jmh</link>
      <guid>https://dev.to/fundamentosjava/118-relatorios-com-datas-4jmh</guid>
      <description>&lt;p&gt;&lt;strong&gt;Agrupamento por data:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usamos YearMonth.from(p.getDate()) para agrupar pagamentos por mês/ano, ignorando dias e horários específicos&lt;/li&gt;
&lt;li&gt;Collectors.groupingBy() é o coletor principal para essa operação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cálculo do valor total por período:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combinamos groupingBy() com reducing() para somar os valores dos pagamentos&lt;/li&gt;
&lt;li&gt;Utilizamos o método getTotalAmount() da classe Payment para obter o valor total de cada pagamento&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contagem de pagamentos por período:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usamos Collectors.counting() para contar quantos pagamentos ocorreram em cada mês&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ordenação dos resultados:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Os resultados são exibidos em ordem cronológica usando sorted(Comparator.comparing(Map.Entry::getKey))&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Visualização dos dados:&lt;/strong&gt;&lt;br&gt;
Mostramos três relatórios diferentes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lista detalhada de pagamentos por mês&lt;/li&gt;
&lt;li&gt;Valor total faturado por mês&lt;/li&gt;
&lt;li&gt;Quantidade de pagamentos por mês&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esta implementação demonstra como gerar relatórios temporais eficientes usando as APIs de data do Java 8 e streams.&lt;/p&gt;

&lt;p&gt;Ver DateReportExample.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>11.7 Qual é nosso cliente mais especial?</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Sat, 19 Apr 2025 04:13:50 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/117-qual-e-nosso-cliente-mais-especial-ndp</link>
      <guid>https://dev.to/fundamentosjava/117-qual-e-nosso-cliente-mais-especial-ndp</guid>
      <description>&lt;p&gt;O "mais especial" pode ser definido por diferentes critérios (ex.: quem gastou mais, quem fez mais compras, etc.).&lt;/p&gt;

&lt;p&gt;Praticar a flexibilidade do Stream API: O código mostrado no livro foca em calcular o total gasto por cliente (Map), assumindo que o "mais especial" é quem contribuiu mais financeiramente (maior valor acumulado).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agrupa os pagamentos por cliente (groupingBy).&lt;/strong&gt;&lt;br&gt;
Soma os valores de todos os pagamentos de cada cliente (reducing).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map&amp;lt;Customer, BigDecimal&amp;gt; totalValuePerCustomer = payments.stream()
    .collect(Collectors.groupingBy(
        Payment::getCustomer,
        Collectors.reducing(BigDecimal.ZERO, paymentToTotal, BigDecimal::add)
    ));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao ordenar o resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;totalValuePerCustomer.entrySet().stream()
    .sorted(Comparator.comparing(Map.Entry::getValue))
    .forEach(System.out::println);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O "cliente mais especial" seria o último da lista (maior valor), no caso do livro:&lt;br&gt;
Adriano Almeida=450&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outros Critérios Possíveis&lt;/strong&gt;&lt;br&gt;
Se "mais especial" tivesse outro significado, o código mudaria. Por exemplo:&lt;/p&gt;

&lt;p&gt;Cliente com mais compras:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map&amp;lt;Customer, Long&amp;gt; countPurchases = payments.stream()
    .collect(Collectors.groupingBy(
        Payment::getCustomer,
        Collectors.counting()
    ));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cliente com o produto mais caro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map&amp;lt;Customer, Optional&amp;lt;Product&amp;gt;&amp;gt; mostExpensiveProduct = payments.stream()
    .collect(Collectors.groupingBy(
        Payment::getCustomer,
        Collectors.flatMapping(
            p -&amp;gt; p.getProducts().stream(),
            Collectors.maxBy(Comparator.comparing(Product::getPrice))
        )
    ));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por Que o Livro Escolheu Esse Exemplo?&lt;/strong&gt;&lt;br&gt;
Didático: Mostra como combinar groupingBy com reducing para resolver problemas complexos.&lt;/p&gt;

&lt;p&gt;Desafio: A versão inicial do código é intencionalmente densa para depois refatorar (com paymentToTotal ou getTotalAmount).&lt;/p&gt;

&lt;p&gt;Preparação: Ensina a pensar em operações aninhadas (redução dentro de redução), úteis para processamento de dados.&lt;/p&gt;

&lt;p&gt;Ver:&lt;br&gt;
SpecialCustomerExample.java&lt;/p&gt;

</description>
    </item>
    <item>
      <title>11.6 Quais são os produtos de cada cliente?</title>
      <dc:creator>FUNDAMENTOS JAVA</dc:creator>
      <pubDate>Tue, 15 Apr 2025 01:14:15 +0000</pubDate>
      <link>https://dev.to/fundamentosjava/116-quais-sao-os-produtos-de-cada-cliente-1hfn</link>
      <guid>https://dev.to/fundamentosjava/116-quais-sao-os-produtos-de-cada-cliente-1hfn</guid>
      <description>&lt;p&gt;Objetivo: Obter um Map&amp;gt; associando cada cliente à lista total de produtos comprados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Abordagem inicial: Agrupando por cliente&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Map&amp;lt;Customer, List&amp;lt;Payment&amp;gt;&amp;gt; customerToPayments =&lt;br&gt;
    payments.stream()&lt;br&gt;
    .collect(Collectors.groupingBy(Payment::getCustomer));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Porém, queremos produtos, não pagamentos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tentativa 1: Mapeando diretamente os produtos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resultado intermediário com listas aninhadas:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Map&amp;lt;Customer, List&amp;lt;List&amp;lt;Product&amp;gt;&amp;gt;&amp;gt; customerToProductsList =&lt;br&gt;
    payments.stream()&lt;br&gt;
    .collect(Collectors.groupingBy(&lt;br&gt;
        Payment::getCustomer,&lt;br&gt;
        Collectors.mapping(Payment::getProducts, Collectors.toList())&lt;br&gt;
    ));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Saída contém List&amp;gt;, o que não é o desejado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solução com duas etapas: Flatten com flatMap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Achatar as listas aninhadas usando flatMap:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Map&amp;lt;Customer, List&amp;lt;Product&amp;gt;&amp;gt; customerToProducts2steps =&lt;br&gt;
    customerToProductsList.entrySet().stream()&lt;br&gt;
    .collect(Collectors.toMap(&lt;br&gt;
        Map.Entry::getKey,&lt;br&gt;
        e -&amp;gt; e.getValue().stream()&lt;br&gt;
              .flatMap(List::stream)&lt;br&gt;
              .collect(Collectors.toList())&lt;br&gt;
    ));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solução em uma única etapa (menos legível)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mesma ideia, mas com tudo encadeado:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Map&amp;lt;Customer, List&amp;lt;Product&amp;gt;&amp;gt; customerToProducts1step = payments.stream()&lt;br&gt;
    .collect(Collectors.groupingBy(Payment::getCustomer,&lt;br&gt;
        Collectors.mapping(Payment::getProducts, Collectors.toList())))&lt;br&gt;
    .entrySet().stream()&lt;br&gt;
    .collect(Collectors.toMap(&lt;br&gt;
        Map.Entry::getKey,&lt;br&gt;
        e -&amp;gt; e.getValue().stream()&lt;br&gt;
              .flatMap(List::stream)&lt;br&gt;
              .collect(Collectors.toList())&lt;br&gt;
    ));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Desvantagem: Código difícil de entender.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solução alternativa com Collectors.reducing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usando reducing para acumular listas de produtos:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Map&amp;lt;Customer, List&amp;lt;Product&amp;gt;&amp;gt; customerToProducts = payments.stream()&lt;br&gt;
    .collect(Collectors.groupingBy(Payment::getCustomer,&lt;br&gt;
        Collectors.reducing(&lt;br&gt;
            Collections.emptyList(),&lt;br&gt;
            Payment::getProducts,&lt;br&gt;
            (l1, l2) -&amp;gt; {&lt;br&gt;
                List&amp;lt;Product&amp;gt; l = new ArrayList&amp;lt;&amp;gt;();&lt;br&gt;
                l.addAll(l1);&lt;br&gt;
                l.addAll(l2);&lt;br&gt;
                return l;&lt;br&gt;
            }&lt;br&gt;
        )&lt;br&gt;
    ));&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Observação: Não existe um método auxiliar no Java para unir listas diretamente, o que exige escrever o BinaryOperator manualmente.&lt;/p&gt;

&lt;p&gt;Exemplo: ProdutosPorClienteExemplo.java&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
