Java-opgraderingskursus

Danmarks Meteorologiske Institut

Dette materiale er under Åben Dokumentlicens, se http://www.sslug.dk/linuxbog/licens.html

Et Javaprogram

Den binære kode - bytecode - i .class-filerne

Platformsuafhængig - dvs. ingen .exe-filer

Platformsafhængig optimering sker først under kørslen

// Et simpelt program, der skriver "Hej verden"

// og et citat af Storm P. ud til skærmen

// filnavn: HejVerden.java

public class HejVerden

{

public static void main (String[] arg)

{

System.out.println("Hej Verden!");

System.out.println("Hvornår smager en Tuborg bedst?");

System.out.println("Hvergang!");

}

}

JBuilder og projekter

Projektet holder rede på filer og egenskaber for programmet

ikke det samme som et katalog

projekter ligger ofte i C:\jbproject

Problemer med stier?

Tjek at projektet forventer kildetekst det rigtige sted!

Tjek stierne i projektet

Åbn "Project Properties"

Kildekode i src/

.class-filer i classes/

Sti på .java-fil = src/ + pakke

Løkker

De simple typer

Arrays

Klassens anatomi

// Klassenavn skal være i filen Klassenavn.java

import klasser;	// f.eks. import java.util.*;

public class Klassenavn

{

// erklæring af variabler (og evt. samtidig initialisering)

adgang type navnPåObjektvariabel;

private String s2 = "goddag"; // samtidig initialisering

// erklæring af konstruktører, evt. med parametre

adgang Klassenavn(type1 parameter1, type2 parameter2, ...)

{

... // kode der sætter objektvariablerne til startværdier

}

// erklæring af metoder, evt. med parametre

adgang returtype metodenavn(type1 parameter1, type2 parameter2, ...)

{

... // kode

}

// eksempler på metoder:

public int metode1()

{

return 15; // noget af type int

}

public void metode2(int nn, String ss)

{

}

}

public class Boks3

{

private double længde, bredde, højde;

public Boks3()

{

System.out.println("Standardboks oprettes");

sætMål(10, 10, 10);

}

/** en anden konstruktør der får bredde, højde og længde */

public Boks3(double lgd, double b, double h)

{

System.out.println("Boks oprettes med lgd="+lgd+" b="+b+" h="+h);

sætMål(lgd,b,h);

}

public void sætMål(double lgd, double b, double h)

{

if (lgd<=0 || b<=0 || h<=0) {

System.out.println("Ugyldige mål. Bruger standardmål.");

længde = 10.0;

bredde = 10.0;

højde = 10.0;

} else {

længde = lgd;

bredde = b;

højde = h;

}

}

public double volumen()

{

double vol = længde*bredde*højde;

return vol;

}

}

Synlighed

Arv

En klasse kan arve variabler og metoder fra en anden klasse

Klassen, der nedarves fra, kaldes superklassen

Klassen, der arver fra superklassen, kaldes underklassen

Underklassen kan tilsidesætte (omdefinere) metoder arvet fra superklassen ved at definere dem igen

Nedarving

public class Boks3medDensitet extends Boks3

{

private double densitet;

public Boks3medDensitet()

{

// super(); kaldes hvis intet andet angives

densitet = 10.0;

}

public Boks3medDensitet(double lgd, double b,

double h, double densitet)

{

// vælg en anden konstruktør i superklassen end den uden parametre

super(lgd,b,h);

this.densitet = densitet;

}

public double vægt()

{

return volumen() * densitet; // superklassen udregner volumen for os

}

}

Arv og konstruktører

Konstruktører skal defineres på ny i en underklasse

En konstruktør kalder først en af superklassens kon­struktører

Superklassens konstruktør kan kaldes med: super(parametre)

Hvis man ikke selv kalder en af superklassens konstruktører, indsætter Java automatisk et kald af superklassens konstruktør uden parametre

UML og klasserelationer

UML og klasserelationer

Rederi og Gade har en Spiller.

Helle, Start, Rederi og Gade er-et Felt.

Samlinger af data

Collection: Samling af data

Indeholder metoder fælles for alle datastrukturer

List: Ordnet liste

To klasser implementerer List: ArrayList og LinkedList.

Set: Uordnet mængde

HashSet implementerer Set.

SortedSet: Sorteret mængde

TreeSet implementerer Set.

Samlinger af data

Eksempel på brug af liste

List liste;

liste = new ArrayList();

liste.add("æh"); // alle samlinger af data

liste.add("øh",0); // kun lister

Gennemløb v.hj.a. tællevariabel

for (int i=0; i<liste.size(); i++) {

String s = (String) liste.get(i);

// gør noget med s

System.out.println(s);

}

Gennemløb v.hj.a. iterator

for (Iterator iter=liste.iterator(); iter.hasNext(); ) {

String s = (String) iter.next();

// gør noget med s

System.out.println(s);

}

Man kan få et iterator-objekt ved at kalde iterator() på enhver datastruktur (Collection)

Et (lille) objekt, der hjælper
med at gennemløbe data

Design-fanen

Visuelt designområde

Struktur af programmet

Egenskaber (og hændelser) på valgt element

Komponentfaner

Visuelt design af et grafisk program

Komponenter er programmørens byggeklodser

De kan bruges igen og igen i mange sammenhænge

De kan sættes sammen på alle mulige måder

De er nemme at indstille

Udviklingsværktøj kan generere programkoden for programmøren

Grafiske brugergrænseflader er som regel helt bygget op af komponenter!

Komponenter i Java hedder Javabønner (eng.: JavaBeans)

Genbrugelige komponenter

Komponentbaseret udvikling

Hule pile: er-en-relationer (dvs. nedarvning)

De andre pile: har-relatioer

En container har nul til mange komponenter

Hver komponent har/tilhører én container

Tilsvarende med CheckboxGroup og Checkbox

Komponenter og containere

Layout-managere

GridBagLayout

BorderLayout

FlowLayout

intet layout (null)

BoxLayout

Persistensproblemet
Strategier til databaseadgang

Rigtig mange muligheder, f.eks.:

JDBC-kode blandet sammen med resten af koden

JDBC-kode i dedikerede klasser

JDBC RowSet - ResultSet, der også opdaterer databasen

CachedRowSet - kan eksistere løsrevet fra databasen

WebRowSet giver XML, der kan transformeres, f.eks. med

XSLT (XSL style sheet)

Javas XML-behandling

EJB - Enterprise JavaBeans - ét serverobjekt pr. række

JDO - Java Data Objects - ét objekt pr. række

Proprietære løsninger

Giver mulighed for grafiske databasekomponenter

Oracle JDeveloper ADF - Application Developer Framework

Borland JBuilder: DataModule

IBM WebSphere Studio

Bedste løsning? Afhænger af omstændighederne!

Hvor omfattende databasedelen af ens applikation er

Hvor meget man forventer den senere skal vedligeholdes.

JDBC – databaseadgang

JDBC – databaseadgang

Lave JDBC-ODBC-bro til Access-fil

Eksempel:

1. Denne computer

2. Kontrolpanel

3. Administration

4.

5.

6

7

Forbindelse til database (MySQL)

Installér MySQL

Hent fra mysql.com

test-database god i starten

Grafiske værktøjer

Installér JDBC-driver

Connector/J fra mysql.com

Læg JAR-fil i java/jre/lib/ext/

Kontakt test-database:

Forberedte SQL-kommandoer

import java.sql.*;

public class ForberedtSQL {

public static void main(String[] arg) throws Exception

{

Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql:///test");

// Forbered kommandoerne til databasen, f.eks. i starten af programmet:

PreparedStatement indsætPstm = con.prepareStatement(

"INSERT INTO kunder (navn,kredit) VALUES(?, ?)");

PreparedStatement hentPstm = con.prepareStatement(

"SELECT navn, kredit FROM kunder WHERE navn=?");

// under programudførelsen kan de forberedte kommandoer udføres mange gange:

for (int i=0; i<100; i++)

{

indsætPstm.setString(1, "Brian");

indsætPstm.setInt(2, i);

indsætPstm.execute();

indsætPstm.setString(1, "Hans' venner"); // bemærk ' i strengen

indsætPstm.setInt(2, 1042+i);

indsætPstm.execute();

hentPstm.setString(1, "Hans' venner"); // bemærk ' i SQL-forespørgslen

ResultSet rs = hentPstm.executeQuery();

// man løber igennem svaret som man plejer

while (rs.next())

{

String navn = rs.getString(1);

double kredit = rs.getDouble(2);

System.out.println(navn+" "+kredit);

}

}

}

}

Samlede batch-opdateringer

import java.sql.*;

public class Batchopdateringer

{

public static void main(String[] arg) throws Exception

{

Class.forName("com.mysql.jdbc.Driver");

Connection con = DriverManager.getConnection("jdbc:mysql:///test");

PreparedStatement pstmt = con.prepareStatement(

"INSERT INTO kunder (navn,kredit) VALUES(?, ?)");

pstmt.setString(1, "Hans");

pstmt.setInt(2, 142);

pstmt.addBatch();

pstmt.setString(1, "Grethe");

pstmt.setInt(2, 242);

pstmt.addBatch();

// send ændringer til databasen

pstmt.executeBatch();

}

}

Uden automatisk commit

import java.sql.*;

public class UdenAutocommit

{

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

try {

forb.setAutoCommit(false);

Statement stmt = forb.createStatement();

stmt.executeUpdate("insert into KUNDER(NAVN,KREDIT) values('Jacob',-17)");

stmt.executeUpdate("insert into KUNDER(NAVN,KREDIT) values('Brian', 0)");

// flere transaktioner ...

System.err.println("Alt gik godt, gør ændringerne forpligtigende");

forb.commit();

}

catch (Exception e)

{

e.printStackTrace();

System.err.println("Noget gik galt! Annullerer ændringerne...");

forb.rollback();

}

finally

{

// Husk at sætte auto-commit tilbage, af hensyn til andre transaktioner

forb.setAutoCommit(true);

}

}

}

Undtagelser og stakspor

Undtagelser

Programudførelsen afbrydes, når der opstår en undtagelse

Kode, hvori der kan opstå en undtagelse og efterfølgende afhængig kode, bør være i samme try-catch-blok

Undtagelser med tvungen håndtering skal enten fanges (med try-catch i metodekroppen) eller sendes videre til kalderen (med throws i metodehovedet)

try

{

... // programkode hvor der er en risiko

... // for at en undtagelse opstår

}

catch (Undtagelsestype u) // Undtagelsestype er f.eks. Exception

{

... // kode som håndterer fejl af

... // typen Undtagelsestype

}

... // dette udføres både hvis ingen undtagelse opstod

... // og hvis der opstod fejl af typen Undtagelsestype

Rydde op med finally

Finally-blokke bliver altid udført, selv når undtagelsen ikke fanges, eller der hoppes ud af metoden på anden vis

public void metode1()

{

try

{

...

if (...) return;

if (...) throw new IllegalArgumentException(...);

...

}

catch (NullPointerException e)

{

System.out.println("Intern fejl:");

e.printStackTrace();

}

finally

{

System.out.println("Dette bliver altid udført.");

}

System.out.println("Slut på metode1()");

}

Metadata

import java.sql.*;

public class BenytMetadataOgUdskrivTabel

{

/** Udskriver et ResultSet pænt. Finder selv ud af kolonnenavnene. */

public static void udskriv(String titel, ResultSet rs) throws Exception {

ResultSetMetaData rsmd = rs.getMetaData();

int antalKolonner = rsmd.getColumnCount();

System.out.println();

System.out.println(" --------- " + titel + " ("+antalKolonner+" kolonner)");

// udskriv kolonnenavnene

for (int i=1; i<=antalKolonner; i++) skrivFormateret(rsmd.getColumnName(i));

System.out.println();

// udskriv cellerne i hver række

while (rs.next())

{

for (int i=1; i<=antalKolonner; i++) skrivFormateret(""+rs.getString(i));

System.out.println();

}

System.out.println(" -----------------------------");

}

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

DatabaseMetaData dmd = forb.getMetaData();

System.out.println("DatabaseProductName = "+dmd.getDatabaseProductName());

System.out.println("DriverName = "+dmd.getDriverName());

System.out.println("MaxRowSize = "+dmd.getMaxRowSize());

ResultSet rs = dmd.getTables(null, "JANO", "%", null);

udskriv("tabeller i databasen", rs);

Statement stmt = forb.createStatement();

rs = stmt.executeQuery("select * from KUNDER");

udskriv("kunder", rs);

}

public static void skrivFormateret(String str) {

System.out.print(str);

String KOL = " | ";

if (str.length()<KOL.length()) System.out.print(KOL.substring(str.length()));

}

}

Metadata

import java.sql.*;

public class BenytMetadataOgUdskrivTabel

{

/** Udskriver et ResultSet pænt. Finder selv ud af kolonnenavnene. */

public static void udskriv(String titel, ResultSet rs) throws Exception {

ResultSetMetaData rsmd = rs.getMetaData();

int antalKolonner = rsmd.getColumnCount();

System.out.println();

System.out.println(" --------- " + titel + " ("+antalKolonner+" kolonner)");

// udskriv kolonnenavnene

for (int i=1; i<=antalKolonner; i++) skrivFormateret(rsmd.getColumnName(i));

System.out.println();

// udskriv cellerne i hver række

while (rs.next())

{

for (int i=1; i<=antalKolonner; i++) skrivFormateret(""+rs.getString(i));

System.out.println();

}

System.out.println(" -----------------------------");

}

public static void main(String[] arg) throws Exception

{

Class.forName("oracle.jdbc.driver.OracleDriver");

Connection forb = DriverManager.getConnection(

"jdbc:oracle:thin:@ora.javabog.dk:1521:student","jacob","jacob");

DatabaseMetaData dmd = forb.getMetaData();

System.out.println("DatabaseProductName = "+dmd.getDatabaseProductName());

System.out.println("DriverName = "+dmd.getDriverName());

System.out.println("MaxRowSize = "+dmd.getMaxRowSize());

ResultSet rs = dmd.getTables(null, "JANO", "%", null);

udskriv("tabeller i databasen", rs);

Statement stmt = forb.createStatement();

rs = stmt.executeQuery("select * from KUNDER");

udskriv("kunder", rs);

}

public static void skrivFormateret(String str) {

System.out.print(str);

String KOL = " | ";

if (str.length()<KOL.length()) System.out.print(KOL.substring(str.length()));

}

}

Opdatere og navigere i ResultSet

De fleste ResultSet har metoder til at bevæge sig aktivt rundt i svaret og endda opdatere databasen gennem svaret.

Det gøres med f.eks.:

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery("select NAVN, KREDIT from KUNDER");

Derefter kan man navigere rundt i ResultSet-objektet med f.eks.:

rs.absolute(3); // går til 3. række i svaret (regnet fra 1 af)

rs.previous(); // går en række tilbage (modsatte af next())

rs.first(); // går til starten af svaret (svarende til rs.absolute(1))

rs.relative(3); // går 3 rækker frem, dvs. til 4. række

int r = rs.getRow();// giver hvilken række vi nu er i (her returneres 4)

Man kan ændre i data med f.eks.:

rs.updateString("NAVN", "Jakob"); // ændrer kundens navn til Jakob

rs.updateRow(); // opdaterer rækken i databasen

rs.moveToInsertRow(); // flyt til speciel indsættelses-række

rs.updateString("NAVN", "Søren"); // sæt navn

rs.updateDouble("KREDIT", 1000); // sæt kredit

rs.insertRow(); // indsæt rækken i databasen

rs.moveToCurrentRow(); // gå væk fra speciel indsættelsesrække

Derudover findes cancelRowUpdates(), der annullerer opdateringer i en række, deleteRow(), der sletter den aktuelle række fra både svaret og databasen, refreshRow(), der opfrisker ResultSet-objektet med de nyeste data.

JDBC RowSet

RowSet = et sæt rækker hentet fra databasen

=ResultSet+oprindelse+ændringer

RowSet-objekter giver mulighed ny arbejdsform

Man behøver kun at spørge på data (f.eks. med SELECT) hvorefter man får et RowSet-objekt.

Når man skal opdatere nogle rækker, slette eller oprette nye, opererer man blot det eksisterende RowSet-objekt

Slut med at rode med INSERT-, DELETE- eller UPDATE-sætninger i SQL.

Flere undertyper af RowSet i JDK 1.5

JdbcRowSet =ResultSet+oprindelse+ændringer

CachedRowSet =rækkerne er gemt i hukommelsen

kan altså eksistere afbrudt fra databasen!

Undertyper: FilteredRowSet og JoinRowSet

WebRowSet =CachedRowSet repræsenteret som XML

JdbcRowSet

CachedRowSet

WebRowSet

Javakursus på DMI

Præsentatoner fra kurset

2004-08-30T12:23:21