Você está na página 1de 35

Arrays em Java

Arrays são objetos que armazenam diversas variáveis do mesmo tipo. Eles podem
conter variáveis de referência primitivas ou de objeto, mas o array propriamente dito
sempre será um objeto da pilha, mesmo se for declarado para armazenar elementos
primitivos. Em outras palavras, não existe algo como um array primitivo, mas você
pode criar um array de elementos primitivos.

Array de 10 elementos

Cada item em um array é chamado de elemento, e cada elemento é acessado pela


posição numérica. Como na ilustração acima as posições são numerdas a partir do 0. O
9th elemento, por exemplo, é acessado na posição 8.

O programa a seguir cria um array de inteiros, atribui algumas posições a ele, e imprime
cada valor à saída padrão.

class ArrayDemo {

public static void main(String[] args) {

int[] meuArray; // declara um array de inteiros

meuArray = new int[10]; // aloca a memória para 10 inteiros

meuArray[0] = 100; // inicializa o primeiro elemento


meuArray[1] = 200; // inicializa o segundo elemento
meuArray[2] = 300; // etc.
meuArray[3] = 400;
meuArray[4] = 500;
meuArray[5] = 600;
meuArray[6] = 700;
meuArray[7] = 800;
meuArray[8] = 900;
meuArray[9] = 1000;

System.out.println("Elemento na posicao 0: " + meuArray[0]);


System.out.println("Elemento na posicao 1: " + meuArray[1]);
System.out.println("Elemento na posicao 2: " + meuArray[2]);
System.out.println("Elemento na posicao 3: " + meuArray[3]);
System.out.println("Elemento na posicao 4: " + meuArray[4]);
System.out.println("Elemento na posicao 5: " + meuArray[5]);
System.out.println("Elemento na posicao 6: " + meuArray[6]);
System.out.println("Elemento na posicao 7: " + meuArray[7]);
System.out.println("Elemento na posicao 8: " + meuArray[8]);
System.out.println("Elemento na posicao 9: " + meuArray[9]);
}
}

A saída desse programa é:

Elemento na posicao 0: 100


Elemento na posicao 1: 200
Elemento na posicao 2: 300
Elemento na posicao 3: 400
Elemento na posicao 4: 500
Elemento na posicao 5: 600
Elemento na posicao 6: 700
Elemento na posicao 7: 800
Elemento na posicao 8: 900
Elemento na posicao 9: 1000

Em uma situação de programação real, você provavelmente utilizaria umas das


construções fazendo loopings (laços) para preencher o seu array, pois seria melhor do
que escrever cada linha individualmente como mostrado acima. Entretanto, este
exemplo ilustra claramente a sintaxe da disposição.

Declarando um array

O programa acima declara meuArray com a seguinte linha de código:

int[] meuArray; // declara um array de inteiros

Como declarações para variáveis de outros tipos, uma declaração de array tem dos
componentes: o tipo do array e o nome do array. O tipo de um array é escrito como
tipo[], onde tipo é o tipo de dados dos elementos contidos no array; os colchetes são
caracteres especiais que indicam que essa variável na verdade é um array.

Como com as variáveis de outros tipos, a declaração não cria realmente o array - diz
simplesmente ao compilador que esta variável terá um array do tipo especificado.

Do mesmo modo você pode declarar arrays de outros tipos:

byte[] meuArrayDeBytes;
short[] meuArrayDeShorts;
long[] meuArrayDeLongs;
float[] meuArrayDeFloats;
double[] meuArrayDeDoubles;
boolean[] meuArrayDeBooleans;
char[] meuArrayDeChars;
String[] meuArrayDeStrings;

Você também pode colocar os colchetes após o nome do array:


float meuArrayDeFloats[]; // forma menos utilizada

Essa forma é menos utilizada, pois com os colchetes antes do nome do array fica mais
fácil entender de que se trata de um array.

Criando, inicializando, e acessando um Array

Uma das formas de se criar um array é utilizando o operador new. A declaração


seguinte no programa ArrayDemo, aloca um array com memória para dez elementos do
tipo inteiro e atribui o array à variável meuArray.

meuArray = new int[10]; // cria um array de inteiros

Se esta declaração faltasse, o compilador imprimiria um erro como o seguinte, e a


compilação falharia:

ArrayDemo.java:9: variable meuArray might not have been initialized

As próximas linhas atribuem valores para cada elemento do array:


meuArray[0] = 100; // inicializa o primeiro elemento
meuArray[1] = 200; // inicializa o segundo elemento
meuArray[2] = 300; // etc.

Cada elemento do array é acessado por seu índice numérico:


System.out.println("Elemento na posicao 0: " + meuArray[0]);
System.out.println("Elemento na posicao 1: " + meuArray[1]);
System.out.println("Elemento na posicao 2: " + meuArray[2]);

Alternativamente, você pode usar atalhos de sintaxe para criar e inicializar um array:
int[] meuArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};

Aqui o tamanho do array é determinado pelo número de valores informados entre { e }.

Você também pode declarar um array de arrays (também conhecido como array
multidimensional), utilizando dois ou mais conjuntos de colchetes [][]. Cada elemento,
deve conseqüentemente ser alcançado por um número correspondente de valores de
índice.

Na linguagem de programação de Java, um array multidimensional é simplesmente um


array cujos os elementos são outros arrays.

Um exemplo de array multidimensional seria:

class ArrayMultiDemo {
public static void main(String[] args) {

String[][] nomes = {{"Mr. ", "Mrs. ", "Ms. "},{"Smith", "Jones"}};

System.out.println(nomes[0][0] + nomes[1][0]); //Mr. Smith


System.out.println(nomes[0][2] + nomes[1][1]); //Ms. Jones

}
}

A saída desse programa é:


Mr. Smith
Ms. Jones

Por fim, você pode utilizar a propriedade length para determinar o tamanho de um
array. O código

System.out.println (meuArray.length);

imprimirá o tamanho do array meuArray.

Espero que tenham gostado do artigo, até o próximo!


Dayvid
Conexão com banco de dados

Olá a todos, nesse artigo irei demonstrar como criar uma conexão com um banco de
dados, estarei utilizando o MySQL mas esse modelo se aplica a qualquer outro banco,
basta apenas para isso trocar o driver de acesso ao banco.

O driver para mysql precisaremos baixar o arquivo mysqlDriver.zip no final desse


artigo, ou de sua fonte original:
http://dev.mysql.com/downloads/connector/j/3.0.html
Pois para que funcione é necessário que o diretório "com" esteja no PATH da máquina
ou seja informado no momento da execução através do parâmetro "-classpath". Para
facilitar estou disponibilizando o arquivo mysqlDriver.zip que contém o driver, para
rodar basta fazer o download do mesmo, colocar o arquivo .zip no mesmo diretório dos
arquivos .java desse artigo e seguir as instruções demonstradas aqui.

Para facilitar a vida de vocês, segue o script de criação da tabela que iremos utilizar no
nosso banco MySQL:

CREATE TABLE `usuario` (


`cod_usuario` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY
KEY ,
`nome` VARCHAR( 255 ) NOT NULL ,
`email` VARCHAR( 255 ) NOT NULL
) ENGINE = MYISAM ;

Para não perder o costume segue primeiramente o código da aplicação e em seguida a


explicação.

Obs.: Esse método de mostrar primeiro o código e depois a explicação eu acabei


adotando por dois motivos e uma experiência pessoal, primeiro que eu tenho todo o
código a mão e segundo a explição faz referências ao código de forma que o código
fique limpo e fácil de entender, e quando acesso algum site de tutorial ou artigos, eu
prefiro que o código fique em uma forma de fácil acesso (copiar e colar por exemplo)
do que ter que baixar um arquivo compactado com o mesmo.
Gostaria da opinião de vocês leitores e amigos para que eu possa disponibilizar os
códigos da melhor forma possível para todos.
Bom vamos voltar ao que realmente interessa.

Primeiro uma breve descrição da nossa aplicação, iremos desenvolver uma aplicação
que recebe "comandos" e parâmetros para o mesmo, podemos informar os comandos:
- incluir: que irá incluir um usuário em nossa base de dados
- excluir: que irá excluir um usuario de nossa base de dados
- listar: que irá listar os usuários cadastrados em nossa base de dados

A aplicação está dividida em duas partes, uma classe com os dados de conexão com
banco e os métodos para incluir, excluir e listar, e uma classe que controla os dados de
entrada do usuário.

Banco.java (classe com métodos do banco de dados)


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Statement;

public class Banco {

private String DRIVER = "com.mysql.jdbc.Driver";


private String URL = "jdbc:mysql://localhost/teste";
private String USERNAME = "usuario";
private String PASSWORD = "senha";
private Connection conn;

public Banco(){
// método construtor quando chamado já irá se
conectar ao banco de dados

try {
Class.forName(this.DRIVER);
this.conn =
DriverManager.getConnection(URL,USERNAME,PASSWORD);

} catch (ClassNotFoundException e){


System.out.println("Não foi possivel encontrar
o driver de banco: " + e.getMessage());
} catch(SQLException e){
System.out.println("Erro ao conectar com o
banco: " + e.getMessage());
}
}

public void listarUsuarios(){


// lista os usuarios cadastrados

Statement stmt = null;


ResultSet rs = null;

// query que será executada


String sql = "SELECT cod_usuario, nome, email FROM
usuario";

try {
// executa a query e guarda o resultado no
RecordSet rs
stmt = this.conn.createStatement();
rs = stmt.executeQuery(sql);
// enquanto houver dados no RS, retira os
campos desejados (cod_usuario, nome e email) e mostra na
tela
while(rs.next()){
// cod_usuario, nome e email são os nomes
dos campos da tabela usuario

System.out.println(rs.getString("cod_usuario") + " - " +


rs.getString("nome") + " - " + rs.getString("email"));

} catch(SQLException e){
System.out.println("erro listando usuarios: " +
e.getMessage());

} finally {
try {
// fecha o stmt e o rs
if(stmt != null) stmt.close();
if(rs != null) rs.close();
} catch (SQLException e){
System.out.println("erro ao tentar fechar o
stmt e o rs: " + e.getMessage());
}
}

public void incluirUsuario(String nome, String email){


// inclui um usuario no banco de dados

Statement stmt = null;

// query que será executada


String sql = "INSERT INTO usuario (nome, email)
VALUES ('"+ nome + "','" + email + "')";

try {
stmt = this.conn.createStatement();
stmt.executeUpdate(sql);

System.out.println("usuário incluido com


sucesso!");

} catch(SQLException e){
System.out.println("erro incluir usuario: " +
e.getMessage());

} finally {
try {
// fecha o stmt
if(stmt != null) stmt.close();
} catch (SQLException e){
System.out.println("erro ao tentar fechar o
stmt: " + e.getMessage());
}
}

public void excluirUsuario(String codUsuario){


// apaga um usuario do banco de dados

Statement stmt = null;

// query que será executada


String sql = "DELETE FROM usuario WHERE
cod_usuario='"+codUsuario+"'";

try {
stmt = this.conn.createStatement();
stmt.executeUpdate(sql);
System.out.println("usuário excluido com
sucesso!");

} catch(SQLException e){
System.out.println("erro excluir usuario: " +
e.getMessage());

} finally {
try {
// fecha o stmt
if(stmt != null) stmt.close();
} catch (SQLException e){
System.out.println("erro ao tentar fechar o
stmt: " + e.getMessage());
}
}

// desconecta do banco de dados


public void desconectar(){
try {
if(this.conn != null) this.conn.close();
} catch(SQLException e){
System.out.println("Erro tentanto fechar a
conexão com o banco: " + e.getMessage());
}
}
}

UsaBanco.java (classe que controla as entradas do usuário)

public class UsaBanco {

public static void main(String[] args){

// define o objeto banco


Banco banco = null;

if(args.length < 1){


System.out.println("Você precisa informar o
comando "incluir", "excluir" ou "listar" e seus argumentos
quando necessário");
System.exit(0);

} else {

if(args[0].equals("incluir")){
System.out.println("Vai incluir");

if(args.length < 3){


System.out.println("Você precisa
informar o nome e email do usuário a ser cadastrado");
System.out.println("Ex.: ");
System.out.println(" java UsaBanco
incluir Dayvid nome@dominio.com");
System.exit(0);
} else {
// os dados foram informados
corretamente
// vai incluir o usuario no banco

// cria o objeto banco e chama o método


para incluir um usuário
banco = new Banco();
banco.incluirUsuario(args[1], args[2]);
banco.desconectar();
}

} else if(args[0].equals("excluir")){
System.out.println("Vai excluir");

if(args.length < 2){


System.out.println("Você precisa
informar o codigo do usuário que deseja excluir");
System.out.println("Ex.: ");
System.out.println(" java UsaBanco
excuir 1");
System.exit(0);
} else {
// os dados foram informados
corretamente
// vai excluir o usuario no banco

// cria o objeto banco e chama o método


para excluir um usuário
banco = new Banco();
banco.excluirUsuario(args[1]);
banco.desconectar();
}

} else if(args[0].equals("listar")) {
System.out.println("vai listar os
usuários");

// aqui listamos os usuários cadastrados no


banco de dados

// cria o objeto banco e chama o método


para listar os usuários
banco = new Banco();
banco.listarUsuarios();
banco.desconectar();

} else {
System.out.println("Comando inválido,
digite o comando "incluir" ou "listar".");
System.exit(0);
}
}
}
}
Executando processos paralelos com a utilização de Threads

Nesse artigo irei demonstrar como podemos executar mais de uma tarefa ao mesmo
tempo utilizando Threads do Java, com esse recurso é possível iniciar mais de um
processo ao mesmo tempo, controlar cada um dos processos a ponto de fazer com que o
seu programa aguarde a finalização dos mesmos para continuar a execução ou fazer
com que o seu programa continue a execução enquanto os processos ainda estão
rodando.

Como sempre estarei colocando primeiro os códigos fonte dos arquivos. Para esse
exemplo estaremos utilizando duas classes, uma que será a nossa "Thread" em si, e a
outra será quem estará controlando/utilizando essa nossa Thread, através desse
controlador iremos instanciar duas vezes a nossa Thread e as duas instancias estarão
rodando ao mesmo tempo.

Para a nossa thread (MyThread) em si criei um exemplo bem simples, é apenas uma
classe que estende o objeto Thread do java, nela temos um método chamado "run", que
quando executado imprime uma mensagem X vezes na tela.

public class MyThread extends Thread {


private String message;
private int qtdRepeticoes = 500;

public MyThread(String message) {


this.message = message;
}
public void run() {
for (int i = 0; i < this.qtdRepeticoes; i++) {
System.out.print(message);
}
System.out.println("FIM da Thread: " + message +
"!");
}
}

Em nossa classe controladora, instanciamos duas vezes o objeto MyThread e em ambas


as instancias chamamos o método "run" - em uma thread o método é "run" porém para
chamá-lo utilizamos "start" e não "run".

public class CallMyThread {

public static void main(String[] args) throws


InterruptedException {

MyThread t1 = new MyThread("a");


MyThread t2 = new MyThread("b");

t1.start();
t2.start();

//t1.join();
//t2.join();

System.out.println("Fim do Programa");

}
}

Entendendo o código:

Agora vamos entender como funciona, primeiro nossa classe MyThread:

Aqui dizemos que nossa classe MyThread é uma subclasse da classe Thread, que é
fornecida pelo pacote java.lang (por isso não precisamos fazer nenhum import).
public class MyThread extends Thread {

O primeiro método da classe é o seu construtor, que recebe uma String e atribui o valor
recebido a variável "message".
public MyThread(String message) {
this.message = message;
}

O método seguinte é o método "run", esse é o método principal dessa classe pois é por
aqui que damos início a execução da mesma.
public void run() {
for (int i = 0; i < this.qtdRepeticoes; i++) {
System.out.print(message);
}
System.out.println("FIM da Thread: " + message +
"!");
}

No nosso caso quando esse método for chamado ele fará com que seja impresso na tela
o valor da variável "message" a quantidade de vezes definida na variável
"qtdRepeticoes" e assim que terminar escreverá "FIM da Thread: X !".

Nota: Eu deixei o número de repetições alto (500) pois caso contrário quando estiver
rodando você não conseguirá ver a execução das duas Threads ao mesmo tempo.

Agora vamos ver a nossa classe CallMyThread, nessa classe temos apenas o método
"main" que cria dois objetos do tipo "MyThread":
MyThread t1 = new MyThread("a");
MyThread t2 = new MyThread("b");

Para o primeiro objeto passamos como parâmetro a letra "a" e para o segundo passamos
a letra "b".

Após instanciar os objetos t1 e t2, invocamos o método "run" deles:


t1.start();
t2.start();
Com isso estamos fazendo as duas threads rodarem, a primeira irá imprimir na tela 500
vezes a letra "a" e a segunda 500 vezes a letra "b".

Notem que para que a segunda thread "t2" rode, não é necessário que a primeira tenha
terminado de executar, ou seja, o programa inicia a "t1", depois a "t2" e em seguida já
mostra na tela "Fim do programa":
System.out.println("Fim do programa");

Como as duas threads estarão rodando ao mesmo tempo, e cada uma delas imprimindo
na tela valores diferentes - "a" e "b", você verá "a" e "b" misturados na tela.

Rode o programa algumas vezes e você terá resultados diferentes a cada vez, em
algumas vezes a frase "Fim do programa" irá aparecer logo no início, outras vezes não e
a seqüência de "a" e "b" será diferente.

Agora você deve estar se perguntando "para que as linhas comentadas?":


//t1.join();
//t2.join();

É bem simples, note que quando você rodou o seu programa na maioria (senão em
todas) as vezes, você recebeu a mensagem "Fim do programa" logo no início, antes
mesmo da seqüência de "a" e "b", isso acontece porque você esta falando para o seu
programa:
1 - criar duas threads
2 - rodar essas duas threads
3 - mostrar a mensagem "fim" na tela

Como estamos criando threads, o programa vai criar as threads como um processo
separado e continuar a sua execução, como o processo de "mostrar a frase fim" é mais
rápido do que fazer um "for" ele acaba mostrando antes das threads rodarem.

Porém existe uma forma de dizer ao programa "Ei, rode as threads ao mesmo tempo,
mas espere até que elas terminem para avançar", isso é feito chamando o método "join"
de cada thread.

Descomente as linhas:
t1.join();
t2.join();

E veja que agora a frase "Fim do programa" sairá sempre no final, depois que as duas
threads já finalizaram.

Nota: A utilização do método "join" por causar uma "InterruptedException", por isso
devemos realizar o tratamento dessa exception, o fazer um "throw" como fazemos aqui.
public static void main(String[] args) throws
InterruptedException {

Esse é um pequeno exemplo de como criar e executar processos paralelos utilizando


"threads", ainda existe muita coisa que não foi abordada aqui, mas espero que esse
artigo tenha ajudado a ter uma visão melhor de como esse processo funciona.
Abraços e até o próximo,
Dayvid
Invocação de Métodos Remotos - RMI

As aplicações do RMI compreendem frequentemente dois programas separados, um


servidor e um cliente. Um programa servidor cria alguns objetos remotos, faz referência
a esses objetos, e aguarda os "clients" invocarem os métodos desses objetos. Enquanto
que um programa cliente obtém uma referência remota ao objetos criados pelo servidor
e invoca os métodos desses objetos.

Entendendo o funcionamento

A seguinte ilustração descreve uma aplicação distribuída RMI que utiliza o "RMI
registry" para obter uma referência a um objeto remoto. O servidor chama o "registry"
para associar (bind) um nome com um objeto remoto. O cliente olha o objeto remoto
por seu nome no "registry" do servidor, e invoca então um método nele. A ilustração
mostra também que o sistema do RMI utiliza um web server existente para carregar
definições da classe, do servidor ao cliente e do cliente ao servidor, para objetos quando
necessário.

Criando aplicações distribuídas usando o RMI

Utilizar RMI para desenvolver uma aplicação distribuída envolve estas etapas gerais:
1 - Projetando e implementando os componentes de sua aplicação distribuída.
2 - Compilando o código fonte.
3 - Fazendo com que as classes sejam acessíveis via rede.
4 - Iniciando a aplicação.

1 - Projetando e implementando os componentes de sua aplicação distribuída.

Para nossa aplicação modelo iremos criar uma classe servidora que irá conter um
método que será invocado remotamente através da utilização de RMI, para isso iremos
precisar de alguns arquivos:
- Ola.java (interface que será implementada tanto pelo server quando pelo client)
- OlaImpl.java (implementação do servidor)
- Cliente.java (client que fará uso de métodos do OlaImpl - server)

Como sempre vamos aos códigos fontes, para esse as explicações serão inseridas na
forma de comentários dentro dos próprios arquivos (assim pouparemos espaço aqui).
Ola.java
Interface que será utilizada tanto pelo servidor quanto pelo cliente, é necessária para
fazer a integração de ambos.

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Ola extends Remote {


String showMsg(String msg) throws RemoteException;
}

OlaImpl.java
Classe que será acessada remotamente pelo Client.java

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class OlaImpl extends UnicastRemoteObject implements


Ola {

// precisamos definir um construtor pois o default não


// gera RemoteException
public OlaImpl() throws RemoteException {
// opcional, vai ser chamado mesmo que não
// o coloquemos aqui
super();
}

public String showMsg(String msg) {


// note que não tem o throws aqui.
// A exceção é gerada pela super-classe se for o
caso

System.out.println("msg: " + msg);


return("msg enviada");
}

public static void main(String args[]) {

try {
// aqui criamos o objeto que sera acessado
// remotamente
OlaImpl obj = new OlaImpl();

// Aqui registramos o objeto obj


como "OlaServidor"
// no servidor
Naming.rebind("OlaServidor", obj);
System.out.println("Servidor carregado no
registry");
} catch (Exception e) {
System.out.println("OlaImpl erro: " +
e.getMessage());
e.printStackTrace();
}
}
}

Client.java
Classe que irá rodar do lado do cliente e utilizará o método "showMsg" da classe
OlaImpl que estará rodando do lado do servidor.

import java.rmi.Naming;

public class Client {

public static void main(String[] args) {

/*
* obj é o identificados que iremos utilizar para
fazer
* referencia ao objeto remoto que será
implementado
*/
Ola obj = null;

String msg = "minha mensagem";


String retorno = null;

try {
/*
* - o lookup carrega o OlaImpl_Stub do
CLASSPATH
* - 127.0.0.1 é o IP da máquina onde o server
* está rodando, no nosso caso é a mesma
máquina
* - OlaServidor é o nome que utilizamos para
fazer
* referencia ao objeto no servidor
*/

// aqui instanciamos o objeto remoto


obj =
(Ola)Naming.lookup("//127.0.0.1/OlaServidor");

// agora executamos o metoro showMsg no


// objeto remoto
retorno = obj.showMsg(msg);
System.out.println(retorno);
}
catch (Exception e) {
System.out.println("Client exception: " +
e.getMessage());
e.printStackTrace();
}
}
}

2 - Compilando o código fonte.

Agora vamos compilar os códigos fonte, para isso basta digitar:


javac *.java

Além da compilação básica devemos criar uma classe do tipo Stub para a classe que
será acessada remotamente, para criar essa classe devemos rodar o comando:
rmic OlaImpl

3 - Fazendo com que as classes sejam acessíveis via rede.

Para que as classes possam ser acessadas via rede, precisamos inicializar o servidor de
rmi através do comando:
start rmiregistry (para linux/unix normalmente é somente rmiregistry)

4 - Iniciando a aplicação.

Agora vamos rodar nossa aplicação, vamos abrir dois prompts do DOS, no primeiro
colocamos o server para rodar com o comando:
java OlaImpl

Com o servidor rodando vamos para a outra janela do DOS e rodamos o client com o
comando:
java Client

Basicamente o que fizemos foi, criar um objeto chamado "OlaImpl" com um método
chamado "showMsg" do lado do servidor, e do lado do cliente criamos um objeto
chamado "Client" que instancia "OlaImpl" e executa o método "showMsg" via RMI.

Veja aqui alguns "screen shots" do Server e do Client rodando em minha máquina:
Server

Client

Essa é uma forma muito utilizada para criar aplicações distribuídas, embora esse artigo
pareça simples, ele demonstra a base para esse tipo de comunicação.

Mais uma vez espero que tenham gostado do artigo e aproveito para agradecer a todos
pelos comentários e o apoio em meus artigos, abraços.

Dayvid
Criando arquivos .jar

Olá a todos, em primeiro lugar gostaria mais uma vez agradecer o apoio, comentários e
críticas de todos vocês.
Nem sempre consigo responder todos os emails e comentários, mas quero que saibam
que todos são lidos e são de grande importância para mim, por tanto muito obrigado.

Muitas pessoas tem me perguntado sobre como trabalhar com arquivos compactados
.jar, pois na maior parte das vezes a nossa aplicação java não se resume apenas a um
arquivo .java, e sim, são compostas de vários arquivos, então como fazer para tornar a
vida mais fácil na hora de um "deploy" ou mesmo no manuseio dos mesmo? A forma
mais fácil é criar um arquivo .jar contendo todos os arquivos do nosso projeto, hoje
veremos como fazer isso utilizando o comando "jar" para criar um pacote "executável"
com os arquivos da nossa aplicação.

Gostaria de dedicar esse artigo ao meus amigos que tem me perguntado sobre
arquivos .jar em especial ao Adriano, foi por causa de suas perguntas que escrevi esse
artigo.

Agora sem mais demora vamos ao que interessa. Para esse artigo iremos precisar de
alguns códigos .java para que possamos gerar o pacote da nossa aplicação, como o
intuito é explicar como gerar o arquivo .jar, os códigos não serão comentados, são
apenas dois códigos simples que escrevi para esta demonstração.

Vamos criar um diretório qualquer para o nosso projeto, eu criei um diretorio chamado
"jarfiles", (que de agora em diante será chamado de diretório RAIZ) e dentro dele
criaremos mais alguns diretórios:
src - diretório onde colocaremos nossos arquivos fonte
bin - diretório onde colocaremos os arquivos compilados

E dentro do diretorio "src" criaremos mais um diretório chamado "init", é um nome


qualquer apenas para mostrar como fazer para rodar um arquivo que estará dentro dele,
e para demostrar que é possível criar diversos diretórios e colocá-los todos no nosso .jar.

Agora que já temos os diretórios iremos criar duas classes dentro do diretório "src/init",
são elas:

OlaMundo.java

package init;

/**
* @author Dayvid Lima
*/

public class OlaMundo {


public void falaOla(){
System.out.println("Olá mundo cruel!");
}
}

UsaOlaMundo.java

package init;

/**
* @author Dayvid Lima
*/

public class UsaOlaMundo {

public static void main(String[] args){


OlaMundo om = new OlaMundo();
om.falaOla();
}
}

Prontinho, agora vamos compilar nossos códigos java para dentro do diretório bin, para
isso uma vez estando dentro do diretório RAIZ no prompt do DOS ou em um terminal
qualquer, vamos digitar:
javac src/init/*.java -d bin/

Isso fará com que os arquivos .java que estão em /src/init/ sejam compilados e
colocados em /bin/init/.

Para ver se está tudo ok iremos rodar nossa aplicação, primeiro entramos no diretório
"bin", e então executamos nossa aplicação com o comando:
java init.UsaOlaMundo

Se tudo der certo veremos a mensagem "Olá mundo cruel!" na tela.

Bom agora que tudo está ok chegou a hora do que realmente interessa, compactar todos
esses arquivos em um único arquivo .jar e rodar a aplicação a partir dele.

Para criar o arquivo .jar iremos fazer uso do comando "jar", existem diversas opções
que podemos passar para o comando jar, iremos nesse artigo fazer uso das seguintes:
c - cria um novo arquivo
v - modo "verbose", mostra na tela o que está acontecendo
f ARQUIVO_JAR - especifica o nome que queremos para o arquivo .jar
m ARQUIVO_DE_MANIFESTO - inclue o arquivo informado como arquivo de
manifesto (veremos isso na segunda parte da explicação)

Ainda dentro do diretório bin, tudo que temos que fazer para criar nosso .jar é executar
o comando:
jar cvf Ola.jar init/*
Pronto, com isso temos nossa aplicação agora dentro do arquivo Ola.jar, vamos então
executá-la, para fazer isso devemos informar no classpath onde está nossa aplicação (no
caso a classe init.UsaOlaMundo),
Podemos tanto colocar o arquivo Ola.jar no nosso classpath quanto informar esse
parâmetro no momento da execução como no comando abaixo:
java -classpath Ola.jar init.UsaOlaMundo

Muito bom, meus parabéns, agora você tem a sua aplicação toda em um arquivo só, pois
bem, vamos facilitar um pouco mais as coisas.

Se olharem dentro do arquivo Ola.jar (abram ele com um compactador qualquer como
Winzip ou Winrar, pois ele é apenas um arquivo compactado sem utilizar compressão,
isso mesmo, você poderia ter simplesmente criado um arquivo .zip ou .rar com o seu
compactador preferido informando a ele para não utilizar compactação, apenas
adicionar os arquivos e depois renomear o mesmo para .jar que ainda assim funcionaria.

Enfim, voltando a aplicação, veja que dentro dele temos um diretório META-INF
contendo o arquivo MANIFEST.MF, pois bem, esse arquivo contém informações sobre
a nossa aplicação, como não criamos esse arquivo, ele tem apenas algumas informações
básica, vamos então criar o nosso MANIFEST.MF e ver em que ele pode nos ajudar.

Quando executamos nossa aplicação vocês se lembram que tivemos que infomar no
classpath o arquivo Ola.jar para que fosse possível rodar a classe "init.UsaOlaMundo",
agora iremos criar um arquivo de manifesto para que seja possível rodar nossa aplicação
informando apenas o arquivo Ola.jar e não mais o nome da classe e pacote
(init.UsaOlaMundo).

Para isso criaremos o nosso próprio MANIFEST.MF, salvem o código abaixo em um


arquivo chamado MANIFEST.MT dentro do diretório "bin".

Manifest-Version: 1.0
Created-By: Dayvid Lima
Main-Class: init.UsaOlaMundo

O mais importante aqui é a última linha "Main-Class: init.OlaMundo", aqui eu digo qual
classe será chamada quando o arquivo Ola.jar for executado.

Arquivo salvo, estamos prontos para continuar. Dentro do diretório bin vamos apagar o
nosso antigo Ola.jar e criar um novo, agora informando qual arquivo de manifesto que
iremos utilizar,
Para isso basta mudar um pouco nosso comando jar como no exemplo abaixo:
jar cvfm Ola.jar MANIFEST.MF init/*

Agora para rodar nossa aplicação precisamos apenas do comando abaixo:


java -jar Ola.jar

E o arquivo MANIFEST.MF se encarrega de dizer a virtual machine qual a classe que


queremos que seja executada.
Anexo deixo para download o arquivo jarfiles.zip, contendo os arquivos citados nesse
artigo para facilitar o trabalho de todos, mais uma vez espero que este artigo tenha sido
satisfatório e que venha a ajudar, até o próximo.

Dayvid
Conexão via Sockets

Hoje iremos criar uma aplicação dividida em duas partes, uma será um "server" que
ficará "ouvindo" uma porta pré-definida por nós e a outra parte será um "client" que fará
o acesso via sockets nesse servidor para trocar informações.

Esse conceito é muito utilizado para realizar acesso a equipamentos e/ou outros
computadores para troca de informações, tanto utilizando aplicações que utilizam um
"server" próprio quanto aplicações que necessitam acessar um outro tipo de servidor
como por exemplo um servidor de Telnet.

Iremos primeiro criar nosso "server", para esse desenvolvimento estou utilizando o
Eclipse (link para ele no final da matéria), porém podemos criar e rodar essa aplicação
sem a utilização de qualquer IDE, apenas tendo o JDK na máquina.

Abaixo seguem os códigos das aplicações.

Server.java

import java.io.*;
import java.net.*;

public class Server {

// porta que esse servidor ficara "ouvindo"


private final int PORT = 5050;

public static void main(String[] args){


Server server = new Server();
server.start();
}

public void start(){

ServerSocket ss = null;
Socket s = null;

OutputStream out = null;


DataOutputStream dataOut = null;

String message = null;

try {
ss = new ServerSocket(this.PORT);
System.out.println("Server on-line na porta: "
+ this.PORT);

while(true){
// espera aqui por algum acesso
s = ss.accept();
System.out.println("usuario conectado");

// cria um canal de comunicao com esse


socket
out = s.getOutputStream();
dataOut = new DataOutputStream(out);

// envia msgs para o cliente quando ele


iniciar uma conexao
dataOut.writeUTF("==== Ola seja bem-vindo
ao Server ====\r\n");
dataOut.writeUTF("- digite algo e tecle
ENTER\r\n");
dataOut.writeUTF("- para sair digite FIM e
tecle ENTER\r\n");
dataOut.writeUTF("- para parar o server
digite SHUTDOWN e tecle ENTER\r\n\r\n");

BufferedReader innet = new


BufferedReader(new InputStreamReader(s.getInputStream()));

// recebe as mensagens enviadas pelo client


while((message = innet.readLine()) != null)
{

System.out.println("msg recebida: " +


message);

// tratamentos especiais
// desconecta o client
if(message.equalsIgnoreCase("fim") ||
message.equalsIgnoreCase("shutdown")){
dataOut.writeUTF("bye bye!");
System.out.println("usuario
desconectado");
innet.close();
break;
}
}
if(message.equalsIgnoreCase("shutdown")){
break;
}
}
}
catch(IOException e){
System.out.println("Erro na inicializacao do
server: " + e.getMessage());
}
finally {
try {
if(s != null) s.close();
if(ss != null) ss.close();
}
catch(IOException e){
System.out.println("Erro ao tentar fechar
as conexoes: " + e.getMessage());
}
}
System.out.println("Servidor finalizado!");
}
}

Client.java

import java.io.*;
import java.net.*;

public class Client {

private final String SERVER_IP = "127.0.0.1"; // IP do


server
private final int SERVER_PORT = 5050; // porta que o
server esta "ouvindo"

Socket echoSocket = null;

public static void main(String[] args){


Client client = new Client();
client.start();
}

public void start(){


PrintWriter out = null;
BufferedReader in = null;
BufferedReader stdIn = null;
String entrada = "";
String mensagem = " ";

try {
echoSocket = new Socket(this.SERVER_IP,
this.SERVER_PORT);
out = new
PrintWriter(echoSocket.getOutputStream(), true);

in = new BufferedReader(new
InputStreamReader(echoSocket.getInputStream()));

// recebe as primeiras linhas enviadas pelo


server
while((mensagem != null) && (!
mensagem.equals(""))){
mensagem = in.readLine();
System.out.println(mensagem);
}

stdIn = new BufferedReader(new


InputStreamReader(System.in));

// envia para o server tudo que o usuário


digitar no client
do {
entrada = stdIn.readLine();
out.println(entrada);
} while ((entrada != null) && !
entrada.equalsIgnoreCase("fim") && !
entrada.equalsIgnoreCase("shutdown"));

// recebe a mensagem de bye bye do server


mensagem = in.readLine();
System.out.println(mensagem);

} catch (UnknownHostException e) {
System.err.println("Nao conseguiu achar o
server " + this.SERVER_IP + ": " + e.getMessage());
System.exit(1);
} catch (IOException e) {
System.err.println("Nao conseguiu abrir a
conexao com o server " + this.SERVER_IP + ": " +
e.getMessage());
System.exit(1);
} finally {
try {
if(stdIn != null) stdIn.close();
if(in != null) in.close();
if(out != null) out.close();
if(echoSocket != null) echoSocket.close();
} catch (IOException e) {
System.err.println("erro ao tentar fechar
as conexoes: " + e.getMessage());
System.exit(1);
}
}
}
}

Entendendo o funcionamento:

O Server:

O que o server faz é ficar "ouvindo" uma determinada porta (no nosso caso a porta
5050), receber tudo que for informado nessa porta e mostrar na tela.
Para isso temos alguns passos básicos:
1 - importar os pacotes necessários para se trabalhar com sockets
2 - definir a porta que queremos "ouvir"
3 - criar a conexão (começar a "ouvir")
4 - mostrar na tela tudo que conseguir capturar pela porta que estamos "ouvindo"

Os pacotes necessários para utilização de sockets são:


import java.io.*;
import java.net.*;

Com eles temos os componentes necessários para criação de um servidor socket, para o
tráfego de dados desse servidor e para os tratamentos de erros (exceptions).

Aqui definimos qual porta queremos que o nosso server fique "ouvindo".
private final int PORT = 5050;

Agora criamos a conexão em sim, é aqui que ele começa a "ouvir" essa porta:
ss = new ServerSocket(this.PORT);

Dizemos ao server para aguardar por alguma conexão:


s = ss.accept();

Assim que ele receber uma conexão na porta que ele está "ouvindo" ele cria um canal de
comunicação com quem acessou essa porta:
out = s.getOutputStream();
dataOut = new DataOutputStream(out);

E começa a receber as mensagens enviadas:


BufferedReader innet = new BufferedReader(new
InputStreamReader(s.getInputStream()));

while((message = innet.readLine()) != null){


System.out.println("msg recebida: " + message);
...

Caso a mensagem enviada seja "FIM" ele desconecta o client, e caso a mensagem seja
"SHUTDOWN" ele desconecta o client e para o server.

if(message.equalsIgnoreCase("fim") ||
message.equalsIgnoreCase("shutdown")){
dataOut.writeUTF("bye bye!");
System.out.println("usuario desconectado");
innet.close();
break;
}

Caso a mensagem enviada seja "shutdown" devemos sair também do while(true) por
isso temos esse outro if:
if(message.equalsIgnoreCase("shutdown")){
break;
}

O Client:

O Client acessa uma PORTA em um IP pré-definido, recebe as mensagens de boas-


vindas do servidor, e envia para o server tudo que for digitado.

Para isso também temos alguns passos básicos:


1 - importar os pacotes necessários para se trabalhar com sockets
2 - definir o ip e a porta que queremos acessar
3 - criar a conexão com esse IP e essa PORTA
4 - receber as mensagens de boas-vindas
5 - enviar para o server tudo que for digitado

Os pacotes necessários para utilização de sockets são:


import java.io.*;
import java.net.*;

Com eles temos os componentes necessários para fazer a conexão via sockets com
algum servidor, trocar mensagens com o mesmo e para os tratamentos de erros
(exceptions).

Aqui temos duas contantes onde definimos o IP de onde vai estar o server e a porta que
mandamos o server ficar "ouvindo", caso o server esteja na sua própria máquina você
pode deixar o IP como "127.0.0.1".

private final String SERVER_IP = "127.0.0.1"; // IP do


server
private final int SERVER_PORT = 5050; // porta que o
server esta "ouvindo"

Agora criamos a conexão com o server:


echoSocket = new Socket(this.SERVER_IP,
this.SERVER_PORT);
out = new
PrintWriter(echoSocket.getOutputStream(), true);

E recebemos todas as mensagens que o server nos enviar no momento da conexão:


in = new BufferedReader(new
InputStreamReader(echoSocket.getInputStream()));

// recebe as primeiras linhas enviadas pelo server


while((mensagem != null) && (!mensagem.equals(""))){
mensagem = in.readLine();
System.out.println(mensagem);
}
Agora fazemos com que o client fique lendo tudo que for digitado pelo usuário e vá
enviando para o server:
// envia para o server tudo que o usuário digitar no
client
do {
entrada = stdIn.readLine();
out.println(entrada);
} while ((entrada != null) && !
entrada.equalsIgnoreCase("fim") && !
entrada.equalsIgnoreCase("shutdown"));

Fazendo funcionar:

Existem diversas formas de compilar e rodar o programa mostrado aqui, segue abaixo
os passos para rodar a partir da linha de comando do DOS:

1 - salve o primeiro código em um arquivo chamado Server.java


2 - salve o segundo código em um arquivo chamado Client.java
3 - no prompt do DOS e/ou shell do Linux/Unix, vá até o diretório onde salvou os
arquivos
4 - para compilar digite: javac Server.java Client.java
Para rodar a aplicação você irá precisar de duas janelas do DOS , uma para o Server e
outra para o Client.

1 - Abra duas janelas (dois prompts) do DOS e entre no diretório onde você compilou
os arquivos
2 - Na primeira janela você deve executar o Server com o comando: java Server
3 - Na segunda janela você deve executar o Client com o comando: java Client

Agora tudo que for digitado no Client será recebido pelo Server e mostrado na janela do
server.

Você pode rodar o Server em uma máquina e o Client em outra, basta para isso colocar
no Client o endereço IP da máquina onde o Server está rodando. Também é possível
utilizar outra porta para a comunicação;

Veja aqui alguns "screen shots" do Server e do Client rodando em minha máquina:
Server rodando

Client acessando o Server

Espero que tenham gostado do artigo, abraços e até o próximo.


Dayvid
Tipos genéricos em Java (Generics)

Muitas pessoas tem me perguntado sobre "Generics", quem trabalha com


linguagens de programação como C++ já deve estar acostumado, porém, tipos
genéricos vem sendo uma novidade para muitos.
Espero com esse artigo esclarecer algumas dúvidas e dar uma pequena visão do
que é e como pode ser utilizado.

A adoção do uso de tipos genéricos em Java levou muito tempo acredito que pelo
fato da possibilidade de realização de "casting", porém quem nunca se deparou
com uma "ClassCastException" quando acidentalmente tentou realizar um "casting"
para o tipo errado.
Com tipos genéricos através de parametrização a verificação do "casting" é
realizada no momento da compilação, o que torna mais fácil a vida do
programador.

Antes de mostrar o exemplo de tipos genéricos, vamos analisar o seguinte cenário:

Iremos criar duas classes, a primeira "Obj" contém dois métodos (add e get) que
recebem e retornam um tipo "Integer".

public class Obj {

private Integer i;

public void add(Integer i){


this.i = i;
}
public Integer get(){
return this.i;
}
}

A segunda classe utiliza a classe Obj para "guardar" um objeto:

public class UsaObj {

public static void main(String[] args) {

// apenas objetos do tipo Integer podem ser


// armazenados em Obj
Obj integerObj = new Obj();
integerObj.add(new Integer(10));

Integer someInteger = (Integer)integerObj.get();


System.out.println(someInteger);

// se algum programador por exemplo tentar


// colocar uma String dentro de Obj
// não será possível uma vez que add recebe
// apenas um Integer.
// (para ver o erro descomente as linhas abaixo)
/*
Obj stringObj = new Obj();
stringObj.add("Teste");

String someString = (String)stringObj.get();


System.out.println(someString);
*/
}
}

No caso acima, somente é possível colocar em Obj um objeto do tipo Integer, agora
veremos como tipos genéricos pode nos ajudar quando queremos colocar um
Integer ou uma String na classe Obj por exemplo.
Vamos recriar o cenário anterior com a utilização de tipos genéricos.

Veja que agora o tipo de objeto que será armazenado é representado pela letra T,
que também deverá ser informado quando uma instância de Obj for criada.

public class ObjGen<T>{

private T t; // T é o tipo do objeto

public void add(T t){


this.t = t;
}
public T get(){
return this.t;
}
}

Agora vamos criar uma classe que utiliza a classe ObjGen.

public class UsaObjGen {

public static void main(String[] args) {

// veja que agora eu defino que tipo de objetos


// podem ir dentro de ObjGen
// nesse caso Integer
ObjGen<Integer> integerObj = new ObjGen<Integer>();
integerObj.add(new Integer(10));

Integer someInteger = (Integer)integerObj.get();


System.out.println(someInteger);

// agora utilizaremos o mesmo objeto ObjGen para


// guardar um tipo String
ObjGen<String> stringObj = new ObjGen<String>();
stringObj.add("Teste");

String someString = (String)stringObj.get();


System.out.println(someString);
}
}

Generics com "tipo mínimo"

Podemos utilizar um "tipo mínimo" para garantir um tipo obrigatório quando


criamos classes genéricas.

public class ObjMin <T extends Runnable> {

void inicia(T t){


new Thread(t).start();
}
}
Aqui estamos definindo que o tipo do objeto (T) deve ser no mínino um "Runnable".

Criaremos agora uma classe chamada Programa que implementa Runnable e utiliza
o ObjMin.

public class Programa implements Runnable {

public static void main(String[] args){

// veja que defino o objeto ObjMin com o


// tipo Programa (esta mesma classe)
// como o objeto Programa estende Runnable eu
// posso fazer isso
ObjMin<Programa> o = new ObjMin<Programa>();
o.inicia(new Programa());
}

// será executado quando a classe for tratada


// como uma thread e o método start foi chamado
public void run(){
System.out.println("ola");
}
}

Existe ainda algumas aplicações para Generics que não abordei nesse artigo para
não torna-lo muito extenso e chato de ler, a idéia aqui é dar uma pequena amostra
de como funciona.

A utilização de "tipos genéricos" vêm sendo adotada cada vez mais pelos
programadores java, também é possível aplicar "tipos genéricos" em interfaces,
mas uma de suas maiores aplicações (pelo que vi nos trabalhos que realizei) é na
manipulação de lista de objetos.

Espero que este artigo venha a sanar as dúvidas de quem ainda não utilizou "tipos
genéricos" e/ou não conhecia.

Todos os exemplos utilizados aqui estão para download, também inclui um link do
site da Sun onde é possível buscar mais informações sobre os "tipos genéricos"
(Generics).

Abraços a todos e até o próximo.


Dayvid

Você também pode gostar