Pacotes Java
Fonte:
Usemynotes Este post irá ajudá-lo a entender melhor os pacotes em Java, entender seu propósito e como implementá-los.
O que são pacotes em Java
Um pacote em Java é uma forma de agrupar um grupo de classes, interfaces e subpacotes. Os pacotes são usados para criar grupos de classes, interfaces, enumerações relacionadas e assim por diante.
Subpacotes são pacotes que estão dentro de outro pacote. Eles não são importados por padrão, mas você pode importá-los manualmente, se necessário. A especificação de acesso não é fornecida aos membros individuais de um subpacote; eles são tratados como pacotes separados.
Alguns tipos de pacotes em Java:
- java.lang - vem junto com Java por padrão.
- java.io - contém classes, métodos e outros elementos relacionados à entrada/saída.
Por que os pacotes são necessários?
- Para evitar conflitos de nomes.
- Para fornecer acesso controlado.
- Para conseguir o encapsulamento de dados.
Como criar um pacote em Java?
Vamos criar um pacote chamado
computador . Normalmente, o nome do pacote é escrito em letras minúsculas. Isso é feito apenas para evitar conflitos de nomes com nomes de classes. Também criaremos uma interface chamada
Pluggable , que estará localizada no pacote
do computador .
package computer;
interface Pluggable {
public void pluggedIn();
public void pluggedOut();
}
Agora criaremos uma classe chamada
PenDrive que implementará a interface acima.
package computer;
public class PenDrive implements Pluggable {
int storage = 64;
public void pluggedIn () {
System.out.println("Pen Drive is connected");
}
public void pluggedOut () {
System.out.println("Pen Drive is removed");
}
public int storage() {
return storage;
}
public static void main(String args[]) {
PenDrive p = new PenDrive ();
p.pluggedIn();
System.out.println("Pen Drive Storage: " + p.storage());
p.pluggedOut();
}
}
Como criar uma hierarquia de pacotes em Java?
Ao formar uma hierarquia, os pacotes em Java são nomeados na ordem inversa. Isso os torna muito semelhantes a diretórios ou pastas. Assim como em um computador pessoal, onde uma pasta pode conter uma ou mais subpastas, o mesmo se aplica aos pacotes em Java. Vejamos um pacote chamado
Asia.India.Kolkata . Todas essas são pastas existentes, mas se você considerar a geografia, fica claro que Calcutá fica na Índia e a Índia fica na Ásia. O principal objetivo de uma hierarquia é tornar as classes mais fáceis de encontrar.
Tipos de pacotes em Java
Pacotes integrados
Pacotes integrados são pacotes que consistem em um grande número de classes integradas que fazem parte da API Java. Esses pacotes incluem:
- java.util - Este pacote contém um número finito de classes utilitárias que são usadas para implementar estruturas de dados, como lista vinculada, conjuntos e assim por diante. Ele também oferece suporte a operações de data e hora e muito mais.
- java.net – Contém classes usadas para operações de rede.
Pacotes definidos pelo usuário
Os pacotes definidos pelo usuário são chamados de pacotes do usuário. O usuário pode criar manualmente um pacote e ter quantas classes desejar.
Como acessar um pacote de outro pacote?
Você pode acessar um pacote de outro pacote de três maneiras simples:
- Usando um asterisco em uma instrução de importação
O caractere asterisco (
* ) é usado para representar “todas as coisas” em Java. Com ele, podemos importar tudo o que está dentro de um subpacote de um pacote.
Exemplo: Considere um pacote chamado
tools . Se quisermos importar tudo o que está dentro deste pacote, precisaremos usar a instrução import como:
import tools.*;
- Usando import package.ClassName;
Mencionar o nome da classe em um pacote é uma forma eficaz de importar apenas as classes necessárias para o seu programa, evitando assim a importação de classes desnecessárias.
Exemplo: Considere um pacote chamado
books . Se quisermos importar apenas uma classe ou interface específica dela (veremos a classe
Pages ), então podemos importar apenas isso usando:
import book.Pages;
Existe uma maneira de usar diretamente um pacote Java ou suas classes usando seu nome completo. Dessa forma você não precisa importar o pacote e pode utilizá-lo diretamente no programa.
Exemplo:
java.awt.List aSimpleList = new java.awt.List();
Tamanho de lote padrão em Java
Por padrão, Java importa o pacote
java.lang . Possui muitas classes que são comumente usadas em programas Java simples, como
String ,
Integer e outros. Uma das classes mais importantes é a classe
Object , que por sua vez também é encontrada no pacote
java.lang . O tamanho deste pacote é baseado em seus componentes: 8 interfaces, 37 classes, 3 enums, 27 exceções, 23 tipos de erro e 5 tipos de anotação.
Métodos Java Thread-Safe para iniciantes
Fonte:
Medium Usando este artigo, você pode aprender sobre o funcionamento de métodos thread-safe em Java. Descobri que muitos desenvolvedores Java júnior/médio não entendem como os métodos thread-safe devem funcionar em projetos reais. E como normalmente trabalhamos em um ambiente multithread, seu uso correto é muito importante. Um método thread-safe é um método que pode ser chamado de vários threads simultaneamente, sem afetar o estado dos dados um do outro. A compreensão insuficiente deste conceito leva a bugs que são difíceis de encontrar e corrigir. Para evitar tais erros, vejamos exemplos.
Exemplo 1:
public static int countLetters(String input) {
int counter = 0;
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
counter++;
}
}
return counter;
}
- O método countLetters é estático, retorna um valor int e aceita um parâmetro string como entrada.
- Um contador de variável primitivo é criado dentro do método, então o loop percorre os caracteres da string de entrada e incrementa o contador de variável cada vez que um caractere de letra é encontrado.
Este método é thread-safe? Muitos desenvolvedores dizem que não, porque neste caso temos uma operação de incremento que não é thread-safe. Vamos descobrir. No modelo de memória Java, temos pilha e heap. Cada thread tem sua própria pilha e todos os threads compartilham o mesmo heap. Nesse sentido, os dados da pilha são sempre thread-safe, mas os dados do heap não. A pilha armazena primitivas e referências de objetos. O heap contém os próprios objetos. Isso significa que neste exemplo de código, cada thread armazena
seu próprio contador de variável na pilha e não tem nenhum efeito nos dados de outros threads, portanto o método é
thread-safe .
Observe que o valor String de entrada também é um objeto, mas String e wrappers primitivos ( Integer , Long , Double , Boolean e assim por diante) são thread-safe porque são imutáveis.
Exemplo #2:
public static int countLetters2(String input) {
List<Character> listCounter = new ArrayList<>();
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
Este código usou a mesma lógica do primeiro exemplo, mas usou um objeto
List em vez de uma variável int primitiva . Da parte anterior sabemos que os objetos em Java são armazenados em heap e
List é um objeto. Também sabemos que a pilha armazena referências a objetos na pilha. No exemplo nº 2, cada thread cria um novo objeto
ArrayList : e a variável
listCounter armazena uma referência ao seu objeto no heap, para que nenhum outro thread possa alterar esse objeto.
List<Character> listCounter = new ArrayList<>();
Isso significa que este método é thread-safe.
Exemplo #3:
public class CounterUtil {
List<Character> listCounter = new ArrayList<>();
public int countLetters3(String input) {
for (Character c : input.toCharArray()) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
}
Neste exemplo, temos uma classe singleton (isso é importante)
CounterUtil com uma variável global
listCounter . Esta variável é criada ao mesmo tempo que a instância singleton. Quando vários threads chamam o método
countChars3 , todos eles usam a mesma variável global
listCounter , que armazena uma referência ao mesmo objeto no heap, e os threads lá influenciarão uns aos outros. Portanto, podemos concluir que este método não é thread-safe. E mesmo se mudarmos
List<Character> listCounter para uma variável primitiva
int counter , também não será thread-safe porque todos os threads usarão a mesma variável primitiva.
Último exemplo:
public static int countLetters4(List<Character> inputList) {
List<Character> listCounter = new ArrayList<>();
for (Character c : inputList) {
if (Character.isAlphabetic(c)) {
listCounter.add(c);
}
}
return listCounter.size();
}
O método
countLetters4 aceita uma lista de caracteres em vez de um parâmetro
String . Aqui
não podemos garantir que este método seja thread-safe. Por que? Porque não podemos ter certeza de como os desenvolvedores usarão esse método. Se outro thread externo alterar os dados em
inputList ao mesmo tempo que nosso método
counterLetters4 , isso poderá afetar o resultado final.
Conclusão
Vimos apenas quatro exemplos e eles não cobrem todos os aspectos da segurança de thread em projetos Java, mas são um bom ponto de partida. Na próxima vez que você vir um método em seu código, pergunte-se: “Este método é thread-safe?” E muito em breve você entenderá claramente a resposta.
GO TO FULL VERSION