# Apostila Java Webdeveloper Basico - Parte 2
## Lista

No Java 17, uma **lista** é uma coleção ordenada de elementos, que permite armazenar múltiplos objetos. A principal interface que representa uma lista no Java é a `java.util.List`, que faz parte da **Java Collections Framework**. Essa interface permite a manipulação de sequências de elementos, onde cada elemento pode ser acessado por sua posição (índice), e pode haver elementos duplicados.
### Principais características de uma lista:
- **Ordenada**: A lista mantém a ordem de inserção dos elementos, ou seja, o primeiro elemento inserido fica na primeira posição e assim por diante.
- **Índice**: Os elementos podem ser acessados diretamente pelo índice.
- **Duplicação**: Permite elementos duplicados.
- **Mutabilidade**: Dependendo da implementação, as listas podem ser mutáveis (permitindo adição e remoção de elementos) ou imutáveis.
### Variações de Lista

As variações da interface `List` dependem da implementação. Abaixo estão as principais implementações e seus conceitos:
**ArrayList**:
- A classe mais comum que implementa `List`. Internamente, é baseada em um array dinâmico.
- **Vantagens**: Acesso rápido por índice (tempo constante, O(1)).
- **Desvantagens**: Inserções e remoções no meio da lista são mais lentas, pois exigem o deslocamento dos elementos.
Exemplo:
```java
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
System.out.println(arrayList); // Saída: [Java, Python]
```
**LinkedList**:
- Implementa `List` utilizando uma estrutura de lista duplamente encadeada.
- **Vantagens**: Inserções e remoções no início ou no meio da lista são rápidas (tempo constante, O(1)).
- **Desvantagens**: O acesso por índice é mais lento, pois precisa percorrer os elementos (tempo linear, O(n)).
Exemplo:
```java
List<String> linkedList = new LinkedList<>();
linkedList.add("Java");
linkedList.add("C++");
System.out.println(linkedList); // Saída: [Java, C++]
```
**Vector**:
- Implementação legada de `List`, semelhante ao `ArrayList`, mas é **sincronizada**, o que significa que pode ser usada em ambientes multithreaded sem a necessidade de sincronização manual.
- **Desvantagens**: Seu uso não é recomendado em novos projetos devido ao overhead de sincronização. Em vez disso, a classe `ArrayList` ou outras opções mais modernas são preferidas.
Exemplo:
```java
List<String> vector = new Vector<>();
vector.add("Java");
vector.add("C#");
System.out.println(vector); // Saída: [Java, C#]
```
**CopyOnWriteArrayList**:
- Implementação de `List` otimizada para cenários em que leituras são mais frequentes que escritas, utilizada em ambientes multithreaded. A cada modificação, uma nova cópia da lista é criada.
- **Vantagens**: Leituras rápidas sem a necessidade de sincronização.
- **Desvantagens**: Modificações são custosas em termos de memória e tempo.
Exemplo:
```java
List<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("Java");
cowList.add("Kotlin");
System.out.println(cowList); // Saída: [Java, Kotlin]
```
### Listas Imutáveis
No Java 17, você pode criar listas imutáveis usando o método `List.of()`, que retorna uma lista que não pode ser modificada (nem adicionar, remover ou alterar elementos). Isso é útil quando você deseja garantir que a coleção permaneça constante.
Exemplo:
```java
List<String> imutableList = List.of("Java", "Go", "Rust");
System.out.println(imutableList); // Saída: [Java, Go, Rust]
// imutableList.add("Python"); // Lançará UnsupportedOperationException
```
Essas são as principais variações de listas no Java 17, cada uma adequada para diferentes necessidades de desempenho e uso em ambientes multithreaded ou mutáveis.
.
.
.
## Collections

No Java 17, a **Collections Framework** continua a desempenhar um papel fundamental na manipulação de estruturas de dados. Ela fornece uma série de interfaces, classes e algoritmos que facilitam o gerenciamento de coleções de objetos de maneira eficiente e flexível. A **Collections Framework** inclui interfaces como `List`, `Set`, `Map`, `Queue`, e suas implementações, oferecendo diversas opções para armazenar e manipular dados.
### Principais Interfaces da Collections Framework
1. **List**:
- Uma coleção ordenada que permite elementos duplicados e permite acesso por índice.
- Implementações: `ArrayList`, `LinkedList`, `Vector`, `CopyOnWriteArrayList`.
2. **Set**:
- Uma coleção que não permite elementos duplicados. Não possui ordem garantida, exceto em implementações específicas.
- Implementações:
- **HashSet**: Não garante ordem dos elementos e permite inserção rápida.
- **LinkedHashSet**: Mantém a ordem de inserção dos elementos.
- **TreeSet**: Mantém os elementos ordenados de acordo com a ordem natural ou por um comparador.
Exemplo com `HashSet`:
```java
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
set.add("Java"); // Não será adicionado, pois já existe
System.out.println(set); // Saída: [Java, Python]
```
3. **Map**:
- Uma coleção de pares chave-valor, onde cada chave é única.
- Implementações:
- **HashMap**: Permite inserções rápidas sem garantir ordem.
- **LinkedHashMap**: Mantém a ordem de inserção dos elementos.
- **TreeMap**: Mantém as chaves ordenadas.
- **Hashtable**: Semelhante ao `HashMap`, mas sincronizado (legado).
Exemplo com `HashMap`:
```java=
Map<String, String> map = new HashMap<>();
map.put("Java", "Linguagem de Programação");
map.put("Python", "Linguagem de Programação");
System.out.println(map); // Saída: {Java=Linguagem de Programação,
Python=Linguagem de Programação}
```
4. **Queue**:
- Uma coleção que segue o princípio FIFO (first-in, first-out), ideal para filas e buffers.
- Implementações:
- **LinkedList**: Implementa `Queue`, além de `List`.
- **PriorityQueue**: Ordena elementos com base em sua prioridade.
- **ArrayDeque**: Implementação de deque (fila dupla), que permite inserções e remoções tanto do início quanto do fim da fila.
Exemplo com `Queue`:
```java=
Queue<String> queue = new LinkedList<>();
queue.add("Primeiro");
queue.add("Segundo");
System.out.println(queue.poll()); // Saída: Primeiro
```
5. **Deque** (Double Ended Queue):
- Uma extensão de `Queue` que permite inserções e remoções de ambos os lados (início e fim).
- Implementações: `ArrayDeque`, `LinkedList`.
### Implementações e Características Específicas
1. **ArrayList**: Baseada em um array redimensionável, ideal para acesso rápido por índice.
2. **LinkedList**: Estrutura de lista encadeada, eficiente para inserções/remoções no meio da coleção.
3. **HashSet**: Baseado em `HashMap`, armazena elementos de maneira não ordenada.
4. **TreeSet**: Baseado em `TreeMap`, armazena elementos de maneira ordenada.
5. **HashMap**: Coleção de pares chave-valor que permite inserções rápidas e não garante a ordem das chaves.
6. **ConcurrentHashMap**: Uma variante do `HashMap` que permite operações eficientes em ambientes multithreaded.
### Novidades em Java 17
Embora a estrutura básica da Collections Framework permaneça a mesma, Java 17 consolidou várias melhorias introduzidas em versões anteriores, como o uso de métodos de fábrica para criar coleções imutáveis.
- **Métodos de fábrica** (`List.of()`, `Set.of()`, `Map.of()`):
- Introduzidos no Java 9 e presentes no Java 17, esses métodos facilitam a criação de coleções imutáveis de forma concisa. As coleções criadas com esses métodos não podem ser modificadas após a criação, o que as torna seguras para uso em ambientes onde a imutabilidade é necessária.
Exemplo de lista imutável:
```java=
List<String> languages = List.of("Java", "Python", "C++");
// languages.add("Ruby"); // Lançará UnsupportedOperationException
```
### Manipulação com Collections Utility Class
A classe `java.util.Collections` contém diversos métodos estáticos que ajudam a trabalhar com coleções, como ordenação, busca, rotação, etc.
- **Ordenação**:
```java=
List<String> list = new ArrayList<>(List.of("Banana", "Apple", "Mango"));
Collections.sort(list); // Ordena a lista
System.out.println(list); // Saída: [Apple, Banana, Mango]
```
- **Reversão**:
```java=
Collections.reverse(list);
System.out.println(list); // Saída: [Mango, Banana, Apple]
```
- **Busca binária** (lista deve estar ordenada):
```java=
int index = Collections.binarySearch(list, "Banana");
System.out.println(index); // Retorna o índice da posição de "Banana"
```
### Sincronização de Coleções
Embora as coleções como `ArrayList` e `HashMap` não sejam sincronizadas por padrão, você pode usar métodos de utilidade para sincronizá-las:
```java=
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
```
### Coleções Imutáveis
Java 17 reforça o uso de coleções imutáveis, úteis em situações onde a imutabilidade é crucial para evitar erros de concorrência:
```java=
Set<String> immutableSet = Set.of("Java", "Python", "Go");
// immutableSet.add("Rust"); // Lançará UnsupportedOperationException
```
A **Collections Framework** no Java 17 oferece uma ampla gama de estruturas de dados que podem ser usadas em diferentes cenários, desde listas e filas simples até conjuntos e mapas otimizados. As implementações são projetadas para serem eficientes e flexíveis, com opções tanto para ambientes multithreaded quanto para cenários onde a imutabilidade é necessária.
.
.
.
## HashMap

*classe pública HashMap <K, V>*
*extends AbstractMap <K, V>*
*implementa o Mapa <K, V>, Cloneable , Serializable*
Implementação baseada em tabela de hash da interface do Mapa . Essa implementação fornece todas as operações opcionais do mapa e permite valores nulos e a chave nula . (A classe HashMap é aproximadamente equivalente a Hashtable , exceto que ela não está sincronizada e permite nulos.) Essa classe não garante a ordem do mapa; em particular, não garante que a ordem permaneça constante ao longo do tempo.
Essa implementação fornece desempenho em tempo constante para as operações básicas ( get e put ), assumindo que a função hash dispersa os elementos corretamente entre os buckets. A iteração sobre visualizações de coleção requer tempo proporcional à "capacidade" da instância do HashMap (o número de depósitos) mais seu tamanho (o número de mapeamentos de valor-chave). Portanto, é muito importante não definir a capacidade inicial muito alta (ou o fator de carga muito baixo) se o desempenho da iteração for importante.
Uma instância do HashMap possui dois parâmetros que afetam seu desempenho: capacidade inicial e fator de carga . A capacidade é o número de depósitos na tabela de hash e a capacidade inicial é simplesmente a capacidade no momento em que a tabela de hash é criada. O fator de carga é uma medida de como a tabela hash é permitida antes que sua capacidade seja aumentada automaticamente. Quando o número de entradas na tabela de hash excede o produto do fator de carga e a capacidade atual, a tabela de hash é reescrita (ou seja, as estruturas de dados internas são reconstruídas) para que a tabela de hash tenha aproximadamente duas vezes o número de buckets.
[Fonte](https://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html)
Essa classe é a implementação da interface Map mais trabalhada no campo de desenvolvimento.
### Características
• Os elementos não são ordenados;
• É rápida na busca/inserção de dados;
• Permite inserir valore e chaves nulas;
### Métodos úteis
Esses métodos oferece bastante ajuda quando é trabalhado com a interface Map.
• values() - É uma Collection com todos os valores que foram associados a alguma das chaves.
• keySet() - Retorna um Set com as chaves do mapa especificado.
• entrySet() - Retorna um conjunto de Maps contido no mapa configurado, podendo ser possível acessar suas chaves e valores.
• put (Key key, Value value) - Associa um valor a uma chave específica.
Para interagir sobre um mapa é preciso trabalhar com a interface Collection ou métodos set() para converter esse mapa em um conjunto de dados.
### Estrutura do HashMap
O HashMap implementa a interface Map T<K,V>, Cloneable e Serializable, mas o que importa para nós aqui é apenas que ele implementa Map. Perceba que a própria implementação do Map T<K,V> usa Generics para atribuir um key-value para a lista, em outras palavras, com o HashMap e Generics podemos especificamente dizer qual o tipo da nossa chave (string, int, double e etc) e o tipo do nosso valor, que obviamente podem diferir sem problema algum.
## Datas

### Classe Date
A data representa o tempo, um tempo é composto por ano, mês, dia atual, minuto atual, entre outras propriedades que essa classe possui.
Hoje a maioria dos métodos da classe Date estão classificados como deprecated (depreciados), ou seja, são métodos que não são mais utilizados, por isso essa classe foi substituída pela classe Calendar, para haver suporte correto à internacionalização do sistema de datas.
### Classe Calendar
Essa classe pode produzir os valores de todos os campos de calendário necessários para implementar a formatação de data e hora, para uma determinada língua e estilo de calendário. Por exemplo, japonês, americano, italiano, brasileiro entre outros.
A classe Calendar é a mais usada quando se trata de datas, mas como é uma classe abstrata, não pode ser instanciada, portanto para obter um calendário é necessário usar o método estático getInstance().
### DateFormat
Essa classe permite converter informações do tipo String para data do tipo Date, permitindo seguir um formato. Consegue-se trabalhar ao contrário, convertendo um dado do tipo Date para uma String. Por ser uma classe abstrata, não é possível instanciá-la, por isso deve ser usado para método estático getDateInstance(). Sempre quando declarado é preciso importar o pacote java.text.
### Conversões
Às vezes é preciso transformar um texto em uma data ou vice versa, para isso abaixo é exibida a função parse e a classe SimpleDateFormat. Geralmente a classe SimpleDateFormat é mais usada quando trata-se de formatação de datas, pois já no seu construtor, quando instanciada, permite passar como argumento o formato da data desejada.
### Internacionalização das datas
O Java oferece a classe Locale, que permite definir de qual país deseja-se obter o retorno das informações, como data e hora. Nos exemplos acima não foi necessário instanciar essa classe, pois já é detectado automaticamente do computador quais são as configurações regionais..
## Relacionameno OneToOne


Classe `Funcionario` tem `Endereco`.
Criar uma classe `Funcionario` contendo 2 atributos (**código, nome**).
### Funcionario.java
```javascript=
package entity;
public class Funcionario {
private Integer codigo;
private String nome;
}
```
Criar uma classe `Endereco contendo os seguintes atributos: código, bairro, cidade, os construtores, toString e getters e setters.
### Endereco.java
```javascript=
package entity;
public class Endereco {
private Integer codigo;
private String bairro;
private String cidade;
public Endereco() {
}
public Endereco(Integer codigo, String bairro, String cidade) {
super();
this.codigo = codigo;
this.bairro = bairro;
this.cidade = cidade;
}
@Override
public String toString() {
return "Endereco [codigo=" + codigo + ", bairro=" + bairro
+ ", cidade=" + cidade + "]";
}
public Integer getCodigo() {
return codigo;
}
public void setCodigo(Integer codigo) {
this.codigo = codigo;
}
public String getBairro() {
return bairro;
}
public void setBairro(String bairro) {
this.bairro = bairro;
}
public String getCidade() {
return cidade;
}
public void setCidade(String cidade) {
this.cidade = cidade;
}
}
```
Voltando na classe `Funcionario`, criar o relacionamento do funcionário com endereço. Acrescentamos o atributo endereço na classe. Ficando dessa forma:
```javascript=
package entity;
public class Funcionario {
private Integer codigo;
private String nome;
private Endereco endereco;
```
A classe `Endereco` virou um atributo da classe `Funcionario`. Dessa forma indicamos que `Funcionario` tem um `Endereco`. Agora criar os outros métodos restantes (construtores, toString e getters e setters).
```javascript=
public Funcionario() {
// TODO Auto-generated constructor stub
}
public Funcionario(Integer codigo, String nome, Endereco
endereco) {
super();
this.codigo = codigo;
this.nome = nome;
this.endereco = endereco;
}
```
Criar um **construtor cheio completo**, com todos os atributos, incluindo endereço e criar um outro construtor cheio sem o atributo endereço.
```javascript=
public Funcionario(Integer codigo, String nome) {
super();
this.codigo = codigo;
this.nome = nome;
}
```
O **toString** será completo, contendo o endereço, pois é a saída. Imprimirá funcionário contendo endereço.
```javascript=
@Override
public String toString() {
return "Funcionario [codigo=" + codigo + ", nome=" + nome
+ ", endereco=" + endereco + "]";
}
```
E os **getters e setters** de todos os atributos.
```javascript=
public Integer getCodigo() {
return codigo;
}
public void setCodigo(Integer codigo) {
this.codigo = codigo;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Endereco getEndereco() {
return endereco;
}
public void setEndereco(Endereco endereco) {
this.endereco = endereco;
}
```
A classe completa ficará da seguinte forma:
```javascript=
public class Funcionario {
private Integer codigo;
private String nome;
private Endereco endereco;
public Funcionario() {
// TODO Auto-generated constructor stub
}
public Funcionario(Integer codigo, String nome) {
super();
this.codigo = codigo;
this.nome = nome;
}
public Funcionario(Integer codigo, String nome, Endereco endereco) {
super();
this.codigo = codigo;
this.nome = nome;
this.endereco = endereco;
}
@Override
public String toString() {
return "Funcionario [codigo=" + codigo + ", nome=" + nome
+ ", endereco=" + endereco + "]";
}
public Integer getCodigo() {
return codigo;
}
public void setCodigo(Integer codigo) {
this.codigo = codigo;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Endereco getEndereco() {
return endereco;
}
public void setEndereco(Endereco endereco) {
this.endereco = endereco;
}
}
```
Para testar a classe Funcionario fazer um método main.
```javascript=
public static void main(String[] args) {
Funcionario f1 = new Funcionario(10,"Luciana",new
Endereco(10,"Ipanema","Rio de Janeiro"));
Funcionario f2 = new Funcionario();
f2.setCodigo(11);
f2.setNome("Carolina");
f2.setEndereco(new Endereco(11,"Tijuca","Rio de
Janeiro"));
System.out.println(f1);
System.out.println(f2.getCodigo() + "," + f2.getNome() );
System.out.println(f2.getEndereco().getBairro());
}
```
Criamos o objeto do funcionário “f1” e passamos os dados através do construtor cheio. Depois criamos o funcionário “f2” e usamos o construtor vazio, passando os dados através do “set” de cada atributo. Pedimos a impressão do “f1” completa, através do toString e “f2” imprimiremos somente o que foi pedido (código, nome) e (bairro).
## Javadoc

**Javadoc** é um gerador de documentação criado pela Sun Microsystems para documentar a API dos programas em Java, a partir do código-fonte. O resultado é expresso emHTML. É constituído, basicamente, por algumas marcações muitos simples inseridas nos comentários do programa.
Este sistema é o padrão de documentação de classes em Java, e muitas dos IDEs desta linguagem irão automaticamente gerar um Javadoc em HTML.
Ele também provê uma API para a criação de doclets e taglets, que permitem a análise da estrutura de um aplicativo Java. É assim, por exemplo, que o JDiff consegue gerar relatórios de alterações feitas entre duas versões de uma API.
### Tags Javadoc
Os desenvolvedores usam certos estilos de comentários e tags Javadoc ao documentar códigos-fonte. Um bloco de comentário em Java iniciado com /** irá iniciar um bloco de comentário Javadoc, que será incluído no HTML gerado. Uma tag Javadoc começa com um "@" (arroba). Na tabela abaixo, algumas destas tags.
| Tag | Descrição |
|--|--|
| @author | Nome do desenvolvedor|
| @category | Você pode criar categorias para seus códigos, como “utilidades” ou “maipulação” ou “services”, etç, |
| @deprecated | Marca o método como deprecated. Algumas IDEs exibirão um alerta de compilação se o método for chamado.|
| @exception | Documenta uma exceção lançada por um método — veja também @throws.|
| @link | Possibilita a definição de um link para um outro documento local ou remoto através de um URL. |
| @param | Define um parâmetro do método. Requerido para cada parâmetro. |
| @return | Documenta o valor de retorno. Essa tag não deve ser usada para construtores ou métodos definidos com o tipo de retorno void.|
|@see |Documenta uma associação a outro método ou classe.|
|@since |Documenta quando o método foi adicionado a a classe.|
|@throws |Documenta uma exceção lançada por um método. É um sinônimo para a @exception introduzida no Javadoc 1.2.
@version |Exibe o número da versão de uma classe ou um método.|
|{@link XX} |Cria um link para uma classe ou método, o nome da classe ou método deve ser colocado no lugar das letras “XX”|
Para inserir o símbolo @ sem iniciar uma tag Javadoc você pode usar o código de caracter HTML @ e evitar problemas de parsing.
### Para gerar o javadoc
:pencil2: Clicar em Project :arrow_right: Generate Javadoc...

---
:pencil2: Clicar em configure -> Indicar onde se encontra o comando do javadoc -> abrir..

---
:pencil2: Marcar a classe que servira de base para o javadoc -> clicar em browser e indicar onde será salvo os arquivos gerados -> next.

---
:pencil2: Next

---
:pencil2: Alterar o JRE para 1.8 -> finish...

---
:pencil2: Clicar em yes to all.

---
:pencil2: Na pasta onde foi salvo, só clicar em index.html

---
:pencil2: Foi criado a documentação em HTML

---
:pencil2: Clicando no link dados...

## Para criar um componente.
:pencil2: Clicar no projeto com o botão direito -> Export.

---
:pencil2: Java -> JAR File – Next.

---
:pencil2: Marcar o projeto que irá ser exportado -> Finish.

---
:pencil2: No Explorer.

## UUID

### O que é?
**UUID** é um identificador universalmente exclusivo utilizado para identificação de qualquer coisa no mundo da computação. O UUID é um número de 128 bits representado por 32 dígitos hexadecimais, exibidos em cinco grupos separados por hifens, na forma textual8-4-4-4-12 sendo um total de 36 caracteres (32 caracteres alfanuméricos e 4 hifens). Por exemplo:
`3d0ca315-aff9–4fc2-be61–3b76b9a2d798`
O objetivo dos **UUIDs** é possibilitar a identificação unica de uma informação em sistemas distribuídos, sem uma coordenação central. Neste contexto a palavra única deve ser tomada com o significado de “praticamente única” uma vez que os identificadores possuam um tamanho finito, é possível para dois itens diferentes compartilhar do mesmo identificador. O tamanho e o processo de geração do identificador necessitam ser selecionados de forma a tornar esta improbabilidade suficientemente na prática.
### Versões
Em sua representação textual8-4-4-4-12o UUID possui um carácter em específico que representa a versão em que o mesmo foi gerado. Veja o exemplo abaixo:
`xxxxxxxx-xxxx-Vxxx-xxxx-xxxxxxxxxxxx ( O V indica a versão )
3d0ca315-aff9–4fc2-be61–3b76b9a2d798 ( UUID versão 4 )`
* **Versão 1:** são gerados a partir de um tempo e um node id (geralmente o endereço MAC);
* **Versão 2:** são gerados a partir de um identificador (geralmente um id de grupo ou usuário), tempo e um node id;
* **Versões 3 e 5:** produzem UUIDs gerados por hashing de um identificador de namespace e nome;
* **Versão 4:** são gerados usando um número aleatório ou pseudo-aleatório.
### Porque usá-lo?
Existe uma longa discussão se a utilização de IDs incrementais pode ser considerado um vazamento acidental de informação. (Na minha opinião é sim!). Essa questão é abordada com excelência nesse fantástico artigo do Phil Sturgeon.
Normalmente quando criamos uma tabela no banco de dados, adicionamos uma coluna ID (ou qualquer outro nome representativo) como chave primaria sendo auto-increment. Um ID auto-increment é um número inteiro que começa em 1 e é aumentado em +1 sempre que um novo registro é salvo no banco de dados
O problema dessa abordagem é que esse ID acaba sendo exposto nas URLs das aplicações para identificar um recurso em específico. Isso é bastante comum em APIs Rest. Veja um exemplo:

.
Outro ponto que merece atenção é a facilidade na manipulação do ID por ele ser um número inteiro incrementado em +1, pode ser facilmente forjado alterando-se a URL.
### Vantagens de utilizar UUIDs
Abaixo eu listo algumas vantagens na adoção dos UUIDs:
* Descentralização na criação de identificadores únicos.
> Como o UUID segue uma especificação, você pode gera-lo independente do ambiente ou linguagem de programação.
* Facilidade na sincronização de dados.
> Se sua aplicação permitir o uso Offline, você pode gerar registros a partir do cliente e armazena-los localmente. Quando sua aplicação ficar online você não terá problemas ao sincronizar os dados com o servidor, uma vez que os UUIDs são descentralizados e únicos.
>
* Omite a quantidade de registros criados em uma tabela.
* Dificuldade a manipulação da URL.
> Aquele esquema de adicionar +1 não funciona com UUID.
### Desvantagens de utilizar UUIDs
Sim! isso mesmo… No mundo da computação não existe bala de prata e nem tudo são flores. Abaixo eu cito algumas desvantagens:
* Um pouquinho mais complicado de depurar.
> É mais fácil lembrar de um número 56 do que um 3d0ca315-aff9–4fc2-be61–3b76b9a2d798, por exemplo.
>
* Maior uso de espaço, uma vez que o UUID é 4 vezes maior.
* Menor desempenho quando armazenado como string.
> Os UUIDs em sua forma textual são armazenados como campos CHAR (36) no banco de dados. Isso tem um custo de desempenho em tabelas com muitos registros, porque o BD não consegue indexar corretamente esses registros.
.
###### tags: `java` `apostila` `basico`