Interação entre Módulos em Java: Exports e Requires
Aplicações Java complexas são frequentemente divididas em múltiplos módulos para melhorar a organização e a manutenção do código. Para que esses módulos possam colaborar, o Sistema de Módulos da Plataforma Java exige que a comunicação entre eles seja explícita. Este guia explica como fazer um módulo (o provedor) expor suas funcionalidades para que outro (o consumidor) possa utilizá-las.
O projeto de exemplo será composto por dois módulos distintos: operations
e demo
.
A estrutura de diretórios do projeto será a seguinte:
C:\java ├─── demo │ ├─── com │ │ └─── programicio │ │ └─── hello │ │ └─── Hello.java │ └─── module-info.java └─── operations ├─── com │ └─── programicio │ └─── factorial │ └─── Factorial.java └─── module-info.java
O Módulo Provedor: operations
Este módulo fornecerá uma funcionalidade de cálculo. Dentro do diretório operations/com/programicio/factorial
, o arquivo Factorial.java
é definido da seguinte forma:
package com.programicio.factorial;
public class Factorial {
public static int calculate(int n) {
if (n < 0) return -1;
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
return result;
}
}
Por padrão, o sistema de módulos impõe um encapsulamento forte: todos os pacotes são privados e inacessíveis de fora. Para permitir que outros módulos usem a classe Factorial
, seu pacote deve ser exportado explicitamente.
Isso é feito no descritor do módulo, o arquivo operations/module-info.java
:
module operations {
exports com.programicio.factorial;
}
A diretiva exports
torna todos os tipos públicos do pacote com.programicio.factorial
visíveis para outros módulos que dependam de operations
.
O Módulo Consumidor: demo
Agora, no módulo demo
, é preciso declarar que ele irá consumir o módulo operations
. Isso é feito no arquivo demo/module-info.java
com a diretiva requires
.
module demo {
requires operations;
}
Com a dependência declarada e o pacote devidamente exportado pelo provedor, a classe Hello
pode importar e utilizar a classe Factorial
. O arquivo demo/com/programicio/hello/Hello.java
terá o seguinte conteúdo:
package com.programicio.hello;
import com.programicio.factorial.Factorial;
public class Hello {
public static void main(String[] args) {
int a = 5;
int b = Factorial.calculate(a);
System.out.printf("Factorial of %d is equal to %d \n", a, b);
}
}
Compilação e Execução
O processo deve seguir uma ordem lógica: primeiro compilamos o provedor (operations
) e depois o consumidor (demo
). Para manter o projeto organizado, os módulos compilados serão salvos em um diretório chamado appmodules
.
Abra um terminal, navegue até o diretório c:\java
e execute os comandos:
- Compilar o módulo
operations
: O comando salva os arquivos.class
no diretórioappmodules/operations
. - Compilar o módulo
demo
: A flag-p
(--module-path
) informa ao compilador onde encontrar o módulooperations
do qualdemo
depende. - Executar a aplicação: Novamente, a flag
-p
é usada para indicar onde encontrar todos os módulos necessários. A flag-m
(--module
) especifica a classe principal a ser executada.
A sessão completa no terminal ficará assim:
c:\java> javac -d appmodules/operations operations/module-info.java operations/com/programicio/factorial/Factorial.java c:\java> javac -p appmodules -d appmodules/demo demo/module-info.java demo/com/programicio/hello/Hello.java c:\java> java -p appmodules -m demo/com.programicio.hello.Hello Factorial of 5 is equal to 120 c:\java>
Resumo
- Encapsulamento Forte: Por padrão, todos os pacotes de um módulo são privados e inacessíveis a outros módulos.
- Diretiva
exports
: Usada no módulo provedor para tornar um pacote público e visível para outros. - Diretiva
requires
: Usada no módulo consumidor para declarar que ele depende de outro módulo. - Compilação com
-p
: A flag--module-path
(ou-p
) é essencial para indicar ao compilador onde encontrar os módulos dependentes. - Execução com
-p
e-m
: Para executar uma aplicação modular, é preciso especificar o caminho dos módulos (-p
) e a classe principal a ser executada (-m
).