Mòdul 4   

Pràctica 3: Classificar, ordenar i empaquetar
Tornar presentació tema
    Pràctica 1 Pràctica 2 Pràctica 3 Pràctica 4 Pràctica 5  
     
 

Tots els llenguatges de programació moderns, com Java, són modulars. Tots organitzen la major part d'habilitats del llenguatge en subconjunts de codi -llibreries, paquets, mòduls ...- que el programador pot decidir incorporar als seus projectes. D'aquesta forma s'optimitza el treball de disseny de programari. Pensa en els avantatges: els projectes incorporen només allò que necessiten, és molt senzill intercanviar codi entre programadors o empreses, el llenguatge es fa molt fàcil d'ampliar només afegint llibreries, etc.

Cada llenguatge, però, planifica la modularitat de manera diferent. En aquesta pràctica revisaràs la sintaxi de l'utilització de paquets en Java, aprendràs a crear-ne de propis i els tancaràs en llibreries. Finalment, estudiaràs com s'ha de procedir per indicar al que incorpori llibreries als seus projectes.

 
  Paquets i llibreries  
     
 

Observaràs que hem utilitzat dues expressions: paquets i llibreries. Expliquem què són abans de continuar.

  • Un paquet és un lloc on desar classes. Si tenim un grup de classes relacionades amb el mateix tipus de tasca, és bo que estuguin totes en un paquet. Així doncs, un paquet és un contenidor, una caixa o una carpeta de classes i d'altres paquets. Podem fer paquets que continguin a l'interior classes per a la gestió de fitxers, o classes que serveixen per a modificar cadenes, o classes que serveixen per a tractar amb dates, etc. El nucli de Java està organitzat així; per exemple.

    java.util

    és un paquet dins d'un altre paquet: el paquet util està dins el paquet java. És un paquet que conté un grup de classes amb utilitats generals del llenguatge.

    java.math

    també és un paquet dins d'un altre paquet. Com pots suposar, es tracta d'eines per al tractament matemàtic.

    Seguin aquest criteri, què creus que contenen aquests paquets?:
    • java.text
    • java.io
    • java.security
    • java.applet


    Pràcticament tot el nucli del llenguatge està dins el paquet java. Quan facis el disseny dels treus propis paquets evitaràs batejar-los amb el nom de java, crearies confusions.


  • Una llibreria, en canvi, és un fitxer que porta l'extensió jar i que conté a l'interior, comprimit, un paquet o un grup de paquets. Si vas a la carpeta /lib de la teva distribució de Java veuràs que hi ha diferents fitxers amb extensió jar: es tracta de llibreries que utilitza el kit de Java i que no formen part del nucli del llenguatge.

    Les llibreries són la fòrmula convencional de distribuir classes de Java: un cop tens escrites, ordenades en paquets i revisades les teves classes, les tanques en una llibreria i, movent només un fitxer, podràs incorporar tot el material a projectes futurs o cedir el codi a qui t'interessi. Per a utilitzar-lo, només farà falta indicar-li al compil·lador que ha d'incorporar la llibreria al projecte.

    Potser et preguntaràs com és que has estat fent sentències d'importació (p. ex. import java.util.*) en els darrers programes i, en canvi, no has hagut d'incorporar cap llibreria al projecte. Pensa que totes les importacions les has fet de classes incloses en el paquet java.*. La llibreria que conté aquest paquet no cal carregar-la, el compil·lador la incorpora per defecte. Una cosa similar passa amb les classes que estan incloses en el paquet java.lang. Oi que has creat objectes de la classe String sense cap sentència d'importació? No ens cal perquè String està en el paquet java.lang. Els dissenyadors de Java han pensat que les classes que estan a java.lang són tan centrals i usuals que ens estalvien l'esforç de cridar explícitament a l'importador.

Resumint una mica, Java estructura la modularitat i intercanvi de classes de la forma següent:

Producció de Codi reusable
 
Utilització de Codi reusable
Escriure les classes distribuint-les en paquets amb sentències package.
Tancar els paquets en una llibreria creant un fitxer .jar   Incorporar la llibreria, el fitxer .jar, al projecte
Utilitzar els paquets de la llibreria amb sentències import
PAQUETS
LLIBRERIES
LLIBRERIES
PAQUETS

Repassem, en primer lloc, la sintaxi i lògica d'importació de paquets i després posarem en pràctica la producció de paquets i llibreries i la reutilització de codi.

 
  Sentències d'Importació  
     
 

En aquests darrers mòduls has estat utilitzant sentències d'importació de l'estil

import java.util.ArrayList; o bé
import java.util.*;

Saps que serveixen perquè el compil·lador localitzi una classe o un grup de classes en el paquet on estan desades i, d'aquesta forma, poder-les utilitzar en els nostres programes. Si crees un objecte ArrayList i et descuides de posar la sentència d'importació a la part superior de la classe que estàs escrivint, el compil·lador no sabrà en quina carpeta localitzar aquesta classe i et donarà un error en temps de compil·lació. Primer haurà buscat ArrayList dins de java.lang. Com que l'esmentada classe no està en aquest paquet, l'haurà buscat en el directori arrel del nostre projecte; com que aquí tampoc no hi és, intentarà buscar un paquet java.util entre les llibreries instal·lades; finalment, farà saltar l'error.

 
     
  Amb asterisc o sense    
     
 

Pots importar classes concretes o pots importar paquets sencers. És idèntic fer una importació així:

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

que fer aquesta:

import java.util.*;

Amb la primera, el compil·lador sap trobar només les tres classes citades mentre que amb la segona pot trobar qualsevol classe del paquet util (no pot trobar, però, les classes que hi puguin haber en els paquets que estan dins del paquet util).

Tot i que sembla més senzill, es desaconsella la utilització de l'asterisc en les sentències d'importació. Perquè? per un problema de legibilitat. Forma part dels protocols de bons costums de programació Java. Està demostrat que és més fàcil de llegir (a ulls humans, al compil·lador li és indiferent) una classe que explicita les importacions que una classe que fa importacions genèriques amb asterisc.

 
     
  Presentació correcta    
     
 

Ja has vist que les sentències d'importació s'han d'escriure fora i damunt de la classe. S'han d'escriure en l'espai que hi ha entre la declaració de paquet package i el capçal de la classe. Per exemple:

package asolans;

import java.util.Iterator;

public class Inventari() {
...

No hi ha normes estrictes sobre com s'han d'ordenar les sentències d'importació, tot i que, a efectes de legibilitat, es recomana:

  • Posar les sentències d'importació per ordre alfabètic.
  • Deixar una línia en blanc en importacions procedents de diferents paquets.

Per exemple, aquesta seria una bona ordenació:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

Possiblement ara penses que tot això és una pèrdua de temps: evitar asteriscs, ordenar sentències o separar-les fan créixer el temps de desenvolupament i no t'aporten avantatges directes. Es tracta, però, d'elements que donen qualitat al codi que fas. Si algun dia et contracten per a programar en Java, el teu cap segurament esperarà de tu que produeixis codi homologat i de qualitat. De la mateixa forma que t'agradarà rebre'l a tu si et toca modificar o ampliar un programa existent.

No tot són males notícies: els IDEs professionals tenen en consideració aquests problemes i fan la vida més fàcil al programador: són capaços de fer importacions intel·ligents per a evitar els asteriscs i saben formatar i ordenar les entrades import.

 
     
  Creació de paquets  
 


Imagina que treballes en una empresa de programari. Estàs integrat en un equip de programadors Java que desenvolupa un projecte per a una important multinacional. El grup té la feina distribuïda i a tu t'ha tocat la tasca d'anar preparant utilitats de gestió de fitxers i de cadenes per a la resta de l'equip -oblida't de començar a treballar fent feines massa creatives!-.

L'empresa és diu "Egon Soft" i el projecte que desenvolupeu Ciclop. Tot el programari Java que desenvolupa la teva empresa s'integra en un paquet, amb el nom egonsoft. Tots i cadascun dels projectes de l'empresa tenen el seu paquet. Com que treballem en el projecte Ciclop, tots els integrants de l'equip anirem escrivint classes que posarem dins el paquet egonsoft.ciclop. A tu t'ha tocat fer utilitats, el teu paquet de sortida és, com deus estar imaginant, egonsoft.ciclop.util.

De totes les utilitats del projecte, tu t'encarregues de gestionar dos apartats: utilitats de cadena i utilitats de fitxer. Les primeres les posarem a egonsoft.ciclop.util.string i les segones a egonsoft.ciclop.util.file.

 
     
Obre el BlueJ i crea un nou projecte que es digui utils. Obre l'opció de menú Edita | Nou paquet. Aquesta acció t'obre una caixa on pots donar el nom del paquet que vols crear. Escriu el següent:  
 
 
 


Clica a Accepta i el et crearà un grup de carpetes, les unes dins de les altres: una carpeta que es diu egonsoft, a dins d'egonsoft una carpeta que es diu ciclop i així successivament fins arribar a la carpeta file.

Els paquets, doncs, s'organitzen en carpetes. I aquestes carpetes no són només virtuals: són reals, físiques, les trobaràs a dins de la carpeta del projecte.

Obre la carpeta del projecte utils. Al seu interior trobaràs les carpetes que t'he indicat. A mesura que vagis escrivint les classes a cada paquet, els fitxers *.java i els fitxers compil·lats *.class també els trobaràs dins la carpeta corresponent. Aquesta forma de funcionament fa bastant senzilla l'ordenació de classes en Java.

Per a "navegar" amb el pels paquets, només et cal fer un doble-clic sobre la icona en forma de carpeta amb el nom del paquet que vols revisar.

 

 
   
 


Ara crea el segon paquet: egonsoft.ciclop.util.string seguint el mateix procediment: Editar | Nou Paquet i el nom complet del paquet.

Crearem una classe d'utilitats per a cadena que contingui un mètode per a resoldre el que ens han encarregat: necessitem poder fer substitucions de paraules dins d'una cadena. Donada una cadena n'hem de retornar una altra on totes les incidències d'un patró han de ser substituïdes per un altre patró. Per exemple, en la frase "El vol 5267 amb destinació a París ha estat cancel·lat" hem de poder substituir la cadena París per la cadena Londres i que retorni "El vol 5267 amb destinació a Londres ha estat cancel·lat".

Navega fins a l'interior del paquet string. Crea una nova classe que es digui StringUtil. Obre l'editor i observa com l'expert del ha escrit aquesta primera línia:

 
     
  package egonsoft.ciclop.util.string;  
 


És la marca de paquet. Qualsevol classe que forma part d' un paquet ha de tenir com a primera línia el nom qualificat -sencer- del paquet. No oblidis que no n'hi ha prou amb posar el fitxer amb el codi font de la classe a la carpeta del paquet, la primera línia sempre ha de contenir el nom del paquet.

Substitueix el contingut de la classe que acabes de crear per aquest:

 
     
  package egonsoft.ciclop.util.string;

/**
* @author Angel Solans
* @version 11-may-2004
*
*/

public class StringUtil {

    /**
     * Evitem la instanciació
     */

    private StringUtil() {
    }


    /**
     * Substitueix a "cadena" el Substring "cerca"
     * per "substitueix"
     * @param cadena, cadena a revisar
     * @param cerca, subcadena que busquem
     * @param substitueix, subcadena que substitueix al patró
     * @return la cadena modificada
     */

    public static String replace(String cadena, String cerca,
        String substitueix) {
        int s = 0;
        int e = 0;
        StringBuffer result = new StringBuffer();

        while ((e = cadena.indexOf(cerca, s)) >= 0) {
            result.append(cadena.substring(s, e));
            result.append(substitueix);
            s = e+cerca.length();
        }
        result.append(cadena.substring(s));
        return result.toString();
    }
}

 
     
 


Observa alguna de les peculiaritats de la classe que hem creat:

  • Hem creat un únic constructor i l'hem fet privat: aquesta classe no es podrà instanciar. Prova de crear un objecte de la classe. no et dóna la possibilitat de fer-ho. No ho pots fer amb el botó dret sobre la icona de la classe i, dins del codi tampoc podràs fer això:

    StringUtil stringutil = new StringUtil();

  • Com que no puc instanciar objectes de la classe, tots els mètodes han de ser de tipus static.

Complicar així les coses quin avantatge té?

  • Com a mínim, et facilitarà la utilització de la classe quan després la necessitis, perquè no n'hauràs de crear instàncies. En lloc de fer:

    StringUtil stringutil = new StringUtil();
    String novacadena =
        stringutil.replace
          ("El vol 5267 a París ha estat cancel·lat",        "París","Londres");

    Podràs fer

    String novacadena=
        StringUtil.replace

          ("El vol 5267 a París ha estat cancel·lat",        "París","Londres");

    El codi és més senzill, legible i igualment eficaç.

Observa la rutina de substitució. S'ha utilitzat la classe StringBuffer en lloc d'una String perquè és una classe més eficient a l'hora d'afegir fragments de cadena.

Et veus capaç de modificar el mètode tot substituïnt l'StringBuffer per una String?

Verifica el funcionament del mètode. Recorda que des del has de cridar-lo directament sobre la icona de la classe perquè no en pots instanciar objectes.

 
     
  Crear llibreries  
     
 

Tot i que no hem fet massa feina, només amb aquesta classe ja estàs en condicions d'experimentar la creació de llibreries.

El facilita molt aquesta feina. Amb el projete utils obert tria l'opcio de menú Projecte | Exportar. T'obrirà una caixa com aquesta:

 
     
 
 
     
 

Deixa l'opció incloure font (si no marques aquesta opció la llibreria només contindrà els fitxers compil·lats .class). Clica sobre el botó Continua. El et demanarà en quina carpeta vols deixar la llibreria.

  • Pots crear-te una carpeta específica per a les teves llibreries
  • Pots desar-la en qualsevol lloc de l'ordinador que t'interessi
  • o pots deixar-la en una carpeta que el té destinada per a les llibreries d'usuari, que es carreguen automàticament cada vegada que obres l'entorn.

Triarem aquesta darrera opció.
Deixa la llibreria a c:/Archivos de Programa/BlueJ/lib/userlib (si tens el instal·lat a Archivos de programa). També pots triar posar a la llibreria el nom de fitxer que vulguis. Acceptarem el que ens suggereix el nostre entorn de treball: utils.

Clica sobre el botó Crear.

Busca amb l'explorador del Windows la carpeta on has deixat la llibreria. Trobaràs un petit fitxer d'uns 2k que es diu utils.jar. Ja tens la llibreria a punt per a utilitzar-la on faci falta.

Tanca el i torna'l a obrir: la llibreria utils.jar ja està disponible. Comprova-ho anant a Eines | Preferències i triant la pestanya "Llibreries". Ha de tenir l'aspecte següent:

 
     
 


 
  Utilitzar llibreries  
     
 


Si has deixat la llibreria a userlib ja la pots utilitzar. Si l'has deixat en un altra carpeta l'hauràs d'afegir des de l'opció Eines | Preferències | Llibreries amb el procediment Afegir.

Crea un nou projecte i posa-li de nom ciclop. Utilitzarem el formatador de cadenes que has preparat.

Crea una classe ControlVols amb el següent contingut:

 
     
  import egonsoft.ciclop.util.string.StringUtil;

/**
*
* @author Angel Solans
* @version 11-05-2004
*/

    public class ControlVols {

    /**
     * Mètode constructor per a objectes
     * de la classe ControlVols
     */

    public ControlVols() {
    }

    /**
     * Substitueix una destinació per una altra
     * @param cadena, cadena a substituir
     * @param desti1, desti inicial
     * @param desti2, desti substitut
     */

    public String substitueixDestinacio(String cadena,
        String desti1, String desti2) {
        return StringUtil.replace(cadena,desti1,desti2);
    }

}

 
     
 

Ara podem accedir i utilitzar les classes de la nostra llibreria.

Compila la classe que acabes de crear i veuràs que tot funciona. Això posa de manifest que ja podem accedir i utilitzar les classes de la nostra llibreria, que s'ha inclòs amb la sentència import.

A mesura que vagis treballant amb Java (cosa que succeirà en els mòduls que s'aniran publicant) veuràs la utilitat i la importància del treball amb llibreries per fer efectiva la funció multiplataforma del llenguatge Java.

 
 

 

Tornar al principi