Segédanyagok

Feladatok

Az egyes témakörökhöz feladatai a feladatok.html fájlban találhatóak meg.

A feladatok.zip tartalmazza az anyag példakódjait, illetve a feladatokhoz kapcsolódó fájlokat.

Fordítás, eljárás, ciklus

A Java alapjai

Történet, jellemzők

Java program írása

Fordítás, futtatás (parancssor)

Kódolási konvenció, dokumentáció

Típusok, konverziók

Vezérlési szerkezetek: elágazások

Vezérlési szerkezetek: ciklusok

Vezérlési szerkezetek: ugró utasítások

Osztály, objektum, csomag, import, debug

Emlékeztető: Hello World!

// Fordítás: javac HelloWorld.java
// Futtatás: java  HelloWorld

public class HelloWorld {
    public static void main(String[] args){
        System.out.println("Hello World!");
        // kiírás a sztenderd kimenetre
    }
}

Osztályok és objektumok

A komplex számok osztálya (ComplexPolar.java)

Tesztprogram (ComplexPolarTest.java)

Készítsük el a létrehozott osztály tesztprogramját.

Csomag (package)

Saját csomag készítése

Csomagazonosítók beillesztése a forrásszöveg elejére + importálás:

Fordítás és futtatás

Programok nyomonkövetése, hibakeresése

>jdb
Initializing jdb ...
jdb> help
run [class [args]]        -- start execution of application's main class
print <expr>              -- print value of expression
eval <expr>               -- evaluate expression (same as print)
set <lvalue> = <expr>     -- assign new value to field/variable/array element
locals                    -- print all local variables in current stack frame
stop at <class id>:<line> -- set a breakpoint at a line
step                      -- execute current line
cont                      -- continue execution from breakpoint
exit (or quit)            -- exit debugger

Osztálydefiníció, getter és setter, this, konstruktor, túlterhelés

Osztályok definíciója

Point.java

Készítsük el a Point osztályt (Point.java). - Tulajdonságok: x és y koordináta (mindkettő double típusú) - Művelet: eltolás: dx és dy értékekkel eltolja a pontot (mindkettő double típusú)

// megoldás:
class Point {

    double x;
    double y;

    void move(double dx, double dy) {
        x += dx;
        y += dy;
    }
}

Circle.java

Készítsük el a kört reprezentáló Circle osztályt (Circle.java). - Tulajdonságok: középpont (Point) és sugár (double) - Műveletek: eltolás és nagyítás - eltolás: dx és dy értékekkel eltolja a középpontot (mindkettő double típusú) - nagyítás: egy adott számmal szorozza a sugarat (factor double típusú)

// megoldás:
class Circle {
    Point center;
    double radius;

    void move(double dx, double dy) {
        center.move(dx, dy);
    }

    void enlarge(double factor) {
        radius *= factor;
    }
}

Láthatóság

Motiváció: - az objektum állapotát kívülről ne tudjuk tetszőleges módon megváltoztatni - az osztályokban a metódusok viselkedése a felhasználó számára mindig lényegében egy fekete doboz

Láthatósági módosítók

Minden adattagra és minden metódusra pontosan egy láthatósági (hozzáférési) kategória vonatkozhat, ezért az alább megadott módosítószavak közül pontosan egyet lehet használni minden egyes tag és metódus esetében. A láthatósági kategóriák (módosítószavak) a következők:

Láthatósági reláció

publicprotected⊇félnyilvános⊇private

Módosító

osztály

csomag

leszármazott

mindenki

public

igen

igen

igen

igen

protected

igen

igen

igen

nem

nincs (package-private)

igen

igen

nem

nem

private

igen

nem

nem

nem

Getterek és setterek

A this pszeudováltozó

Készítsünk lekérdező és beállító műveleteket (metódusokat), amelyekkel le tudjuk kérdezni / be tudjuk állítani a pontok és a körök attribútumait:

A metódusok legyenek publikusak.

(Az adattagok nem publikusak.)

Használjuk a this pszeudováltozót.

Főprogram (PointCircleTest.java)

Készítsünk tesztprogramot a pontok és körök osztályához.

  1. Hozzunk létre egy Point és egy Circle objektumot.
  2. Kérdezzük le és állítsuk be a pont koordinátáit.
  3. Toljuk el a pontot megadott értékkel.
  4. Legyen a pont a kör középpontja, állítsuk be a sugarát.
  5. Toljuk el, nagyítsuk a kört.
  6. Kérdezzük le a kör középpontját és a sugarát.

Konstruktorok

Túlterhelés (overloading)

Konstruktorok készítése, túlterhelés

A Point és Circle osztályokhoz készítsünk konstruktorokat. A Point osztályhoz csak egyet, amelynek a koordinátákat lehet átadni. A Circle osztályhoz hármat:

toString

Készítsünk a Point osztályba egy szöveges visszatérési értékű, paraméter nélküli, toString nevű publikus metódust, amely visszaadja egy pont szöveges reprezentációját.

Tömbök használata

Tömegközéppont meghatározása (PointCircleTest.java)

Tömbök, Arrays, String, StringBuilder

Tömbök

Tömb létrehozása

Tömbök inicializálása

Többdimenziós tömbök

int mdt[][];
mdt = new int[2][];
mdt[0] = new int[2];
mdt[0][0] = 7;
mdt[0][1] = 2;
mdt[1] = new int[3];
mdt[1][0] = 2;
mdt[1][1] = 4;
mdt[1][3] = 0;

A java.util.Arrays osztály

void reverse( int[] src, int[] dst ){
    assert src != null;
    assert dst != null;
    assert src.length == dst.length;
    assert src != dst;    
        // ezt is kossuk ki, hogy jol mukodjon
    for( int i=0, j=src.length-1; 
        i<src.length; ++i, --j ){
        dst[j] = src[i];
    }
}
public class Point {
    private final int x,y;
    public Point( int x, int y ){
        this.x = x;
        this.y = y;
    }
    public int getX(){ return x; }
    public int getY(){ return y; }
}
public class Point {
    private final int[] coords;
    public Point( int x, int y ){
        coords = new int[]{x, y};
    }
    public int getX(){ return coords[0]; }
    public int getY(){ return coords[1]; }
    public int[] coords(){ return coords; }
}

Point p = new Point(1,1);
int[] c = p.coords();

Kiszivárogtatás

public class Point {
    private final int[] coords;
    public Point( int x, int y ){
        coords = new int[]{x, y};
    }
    public int getX(){ return coords[0]; }
    public int getY(){ return coords[1]; }
    public int[] coords()
        { return new int[]{coords[0],coords[1]}; }
    // masolatot adunk vissza
}

A String osztály

A StringBuilder osztály

Kivételkezelés, I/O (BufferedReader, Scanner, PrintWriter)

Mi is az a kivételkezelés?

Példa – Magyarázat

Hívási lánc (stack trace)

Exception in thread "main" java.lang.NullPointerException
    at Repeater.println(Repeater.java:6)
    at Main.print(Main.java:13)
    at Main.main(Main.java:5)

Kivételkezelés hibakezelés

Kivételek tehát

Kivételek lekezelése

try {
    // ...
} catch (ExceptionType1 e) {
    // ...
} catch (ExceptionType2 e) {
    // ...
} /*
    ...
*/ catch (ExceptionTypeN e) {
    // ...
} finally {
    // ...
}

Kivételek lekezelése – Példa

public class Main {

    public static void main(String[] args) {
        try {
            System.out.println("Hello, " + args[0] + "!");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.err.println("Not enough command line arguments.");
            // standard error kimenetre írunk
        } finally {
            System.out.println("bye");
        }
    }

}

Kivételek lekezelése – Példa futtatása

$ javac Main.java

$ java Main
Not enough command line arguments.
bye

$ java Main World
Hello, World!
bye

Java IO

Feladat

BufferedReader

String filepath = args[0]; // abszolút vagy relatív út
File file = new File(filepath);
try ( FileReader reader = new FileReader(file) ) {
    // itt használhatjuk a reader objektumot
}
try (FileReader reader = new FileReader(file);
    BufferedReader br = new BufferedReader(reader) ){

    // ...
}
try (BufferedReader br =
    new BufferedReader(new FileReader(file)) ){

    // ...
}

BufferedReader – Kivételkezelés

try (BufferedReader br =
    new BufferedReader(new FileReader(file)) ){

    // ...
} catch (FileNotFoundException e) {
    System.err.println("File does not exist.");
} catch (IOException e) {
    System.err.println("An IO error occurred.");
}

BufferedReader – readLine

try ( BufferedReader br =
    new BufferedReader(new FileReader(file)) ) {

    String line;
    for (line = br.readLine();
        line != null;
        line = br.readLine()) {

        System.out.println(line);
    }
} catch (FileNotFoundException e) {
    System.err.println("File does not exist.");
} catch (IOException e) {
    System.err.println("An IO error occurred.");
}

Scanner

try ( Scanner sc = new Scanner(file) ) {
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        System.out.println(line);
    }
} catch (FileNotFoundException e) {
    System.err.println("File does not exist.");
}

PrintWriter

String[] linesToWrite = // ...

try ( PrintWriter pw = new PrintWriter(file) ) {

    for (String line : linesToWrite) {
        pw.println(line);
    }
} catch (FileNotFoundException e) {
    System.err.println("File cannot be opened.");
}

throws

Túlterhelés, static, alapértelmezett konstruktor, fájlfeldolgozás, felsorolási típus

Túlterhelés - overloading

Egy sokszor látott példa

System.out.println(int);
System.out.println(double);
System.out.println(String);

Túlterhelés - Konstruktor túlterhelése

public class Point {
    private int x, y;
    public Point( int x, int y ){
        this.x = x;
        this.y = y;
    }
    public Point(){
        x = 0;  y = 0;   // amugy is 0
    }
}
public class Point {
    private int x, y;
    public Point( int x, int y ){
        this.x = x;
        this.y = y;
    }
    public Point(){
        this(0,0);
    }
}

Alapértelmezett konstruktor

public class Circle {
    private int x, y;
    private double radius;
    public static void main(String[] args){
        Circle c = new Circle(); // x:0; y:0, radius: 0.0
    }
}

public class Circle {
    private int x = 0, y = 0;
    private double radius = 1.0;   // inicializáló kifejezés
    public static void main(String[] args){
        Circle c = new Circle(); // x:0; y:0, radius: 1.0
    }
}
public class Circle {
    private int x, y;
    private double radius;
    public Circle(int x, int y, int r){/*...*/}
    public static void main(String[] args){
        //compile error:
        //constructor Circle in class Circle cannot be applied to given types;
        Circle c = new Circle();
    }
}

Statikus adattagok

public class Circle {
    public static int counter = 0;
    private int x, y;
    private double radius;
    public Circle(){ counter++; /*...*/}
    public static void main(String[] args){
                System.out.println(Circle.counter);
                Circle c1 = new Circle();
                System.out.println(Circle.counter);
                Circle c2= new Circle();
                System.out.println(Circle.counter);
    }
}

Kimenet:

0
1
2
public class Circle {
        public static int counter = 0;
    private int x, y;  private double radius;
    private static void incrementCounter(){counter++;}
    public Circle(String sx, String sy, String sradius){
                        incrementCounter();
                        x = Integer.parseInt(sx);
    }
    public static void main(String[] args){
                        incrementCounter();
                        System.out.println(Circle.counter);
                        Circle c1 = new Circle("1","2","3");
                        System.out.println(Circle.counter);
    }
}

Kimenet:

1
2
public class Main{
    public static void main(String[] args){
        Circle.incrementCounter(); // -> OK
        System.out.println(Circle.counter); //->OK
        Circle c1 = new Circle("1","2","3");
        c1.incrementCounter(); // ->NEM OK !!
        System.out.println(c1.counter);  // ->NEM OK !!
    }
}
class Circle {
    public static int counter = 0;
    /*...*/
    public static void incrementCounter(){counter++;}
}

Felsorolási típus (enum)

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY
}
//...
Day d1 = Day.MONDAY;
Day d2 = Day.valueOf("MONDAY");
public class EnumTest {
  Day day;
  public EnumTest(Day day) {   this.day = day; }
  public void tellItLikeItIs() {
     switch (day) {
        case MONDAY:
                System.out.println("Mondays are bad.");
             break;
        case FRIDAY:
                System.out.println("Fridays are better.");
              break;
        case SATURDAY: case SUNDAY:
                System.out.println("Weekends are best.");
             break;
        default:
                System.out.println("Midweek days are so-so.");
              break;
        }
    }
    //....
//....
    public static void main(String[] args) {
        EnumTest firstDay = new EnumTest(Day.MONDAY);
        firstDay.tellItLikeItIs();
        EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
        thirdDay.tellItLikeItIs();
        EnumTest fifthDay = new EnumTest(Day.FRIDAY);
        fifthDay.tellItLikeItIs();
        EnumTest sixthDay = new EnumTest(Day.SATURDAY);
        sixthDay.tellItLikeItIs();
        EnumTest seventhDay = new EnumTest(Day.SUNDAY);
        seventhDay.tellItLikeItIs();
    }
}
public enum Planet {
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    //...
    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius)
            { this.mass = mass; this.radius = radius;}
   public static final double G = 6.67300E-11;
   double surfaceGravity()
            {  return G * mass / (radius * radius);    }
    //...
 //..
 double surfaceWeight(double otherMass) {
      return otherMass * surfaceGravity();
 }
  public static void main(String[] args) {
      if (args.length != 1) {
         System.exit(-1);
      }
     double earthWeight = Double.parseDouble(args[0]);
     double mass = earthWeight/EARTH.surfaceGravity();
     for (Planet p : Planet.values())
       System.out.printf("Your weight on %s
       (the %d th planet)  is %f%n",
       p, p.ordinal()+1,p.surfaceWeight(mass));
    }

Tesztelés

Szoftver minőségbiztosítás

Specifikáció (követelmények halmaza) A követelményeket teljesítő (“helyes”) program \

Futtatás során ellenőrizzük a követelmények teljesülését A helyesség (automatikus) levezetése a (formális) specifikációból Helyes program levezetése a specifikációból …

Tesztelés

Mit tesztelünk?

Tesztelés

Mekkora egységet tesztelünk?

Legkisebb önállóan működő alapegységeit (osztály, metódus) Összetartozó egységek együttműködését (csomag). Rendszer, alkalmazás egészét fejlesztői oldalról. Nem-funkcionális követelmények, használati esetek. Üzembehelyezett rendszer, alkalmazás egészét felhasználói oldalról.

Egységteszt

A rendszer legkisebb önállóan működő egységeit teszteli (osztály, metódus).

Célok:

Elvárások:

JUnit 4

A tesztek általános szerkezete

Tippek egységtesztek tervezéséhez

Tesztelés: fehérdobozos

Milyen a jó teszt?

FIRST elvek

Fehérdoboz-tesztelés

Teszt-lefedettségi mutatók

Interfészek, Öröklődés, Sablonok

Öröklődés

Osztályhierarchia

Az Object osztály

Láthatósági módosítók (emlékeztető)

Minden adattagra és minden metódusra pontosan egy láthatósági (hozzáférési) kategória vonatkozhat, ezért az alább megadott módosítószavak közül pontosan egyet lehet használni minden egyes tag és metódus esetében. A láthatósági kategóriák (módosítószavak) a következők:

Láthatósági reláció (emlékeztető)

publicprotected⊇félnyilvános⊇private

Módosító

osztály

csomag

leszármazott

mindenki

public

igen

igen

igen

igen

protected

igen

igen

igen

nem

nincs (package-private)

igen

igen

nem

nem

private

igen

nem

nem

nem

A super pszeudováltozó

Felüldefiniálás

A felüldefiniálás szabályai

Az öröklődés szemléltetése egy példán

A példába tartozó fájlok:

Kompozíció

class Person {

    private String  name;  /* String  "is part of" Person */
    private Integer age;   /* Integer "is part of" Person */

    public static Person make(String name, Integer age) {
        return ((age > 0 && !name.isEmpty()) ?
            new Person(name, age) : null);
    }

    private Person(String name, Integer age) {
        this.name = new String(name);
        this.age  = new Integer(age);
    }
    ...
    ...
    public String getName() {
        return new String(name);
    }

    public Integer getAge() {
        return new Integer(age);
    }

    public String toString() {
        return String.format
            ("Person { name = %s, age = %d }", name, age);
    }
}

Aggregáció

class Person {
    private String name;
    /* String  "is part of" Person */
    private Integer age;
    /* Integer "is part of" Person */
    private ArrayList<Person> friends;
    /* Person  "has" Persons */

    public static Person make(String name, Integer age) {
        return ((age > 0 && !name.isEmpty()) ?
            new Person(name, age) : null);
    }

    private Person(String name, Integer age) {
        this.name    = new String(name);
        this.age     = new Integer(age);
        this.friends = new ArrayList<Person>();
    }
    ...
    ...
    public String getName() {
        return new String(name);
    }

    public Integer getAge() {
        return new Integer(age);
    }

    public void addFriend(Person friend) {
        friends.add(friend);
    }

    public String toString() {
        return String.format
        ("Person { name = %s, age = %d, friends = %s }",
          name, age, friends.toString());
    }
}

Interfészek

Interfészek definíciója

Interfészt megvalósító osztály

Öröklődés

Relációk a referenciatípusokon

Interfész megvalósítása

Az interfész mint típus

Az interfész mint típus – változódeklarációkban

I v = new A();
J w = new B();

Az interfész mint típus – formális paraméterek specifikációjában

Generikus interfészek

Típussal paraméterezhető interfészek

public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
    this.key = key;
    this.value = value;
    }

    public K getKey()   { return key; }
    public V getValue() { return value; }
}
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<String, String>("hello", "world");

equals és hashCode, Comparable, Set, Map, absztrakt osztály, kivételek

Objektumok összehasonlítása

Egyenlőségvizsgálat az equals-zal

A hashCode metódus

Az equals metódus felüldefiniálása – tulajdonságok

Az equals metódus felüldefiniálása – sablon

public class Person {
    private String name;
    private int birthYear;
    
    public Person(String name, int birthYear) {
        this.name = name;
        this.birthYear = birthYear;
    }

    public String getName() {
        return name;
    }
    
    public int getBirthYear() {
        return birthYear;
    }
    
    ... // equals és hashCode

}
@Override
public boolean equals(Object obj) {
    if (obj == this) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if ( !(obj instanceof Person) ) {
        return false;
    }

    Person other = (Person) obj;

    ...
    // Referenciatípusnál két null-t egyenlőnek kell venni,
    // null-t és nem null-t különbözőnek
    if (name == null) {
        if (other.name != null) {
            return false;
        }
    } else if (!name.equals(other.name)) {
        return false;
    }

    // Primitívnél egyszerű a dolgunk: nem lehet null
    if (birthYear != other.birthYear) {
        return false;
    }
    return true; // Minden oké, visszatérhetünk igazzal
}

A hashCode metódus felüldefiniálása

Comparable

compareTo

@Override
public int compareTo(Person other) {
    int compare = this.name.compareTo(other.name);
    if (compare != 0) {
        return compare;
    }
    // Ha már itt eldőlt, hogy valamelyik objektum kisebb,
    // térjünk vissza. Különben vizsgálódunk tovább.

    if (this.birthYear < other.birthYear) {
        compare = -1;
    } else if (this.birthYear > other.birthYear) {
        compare = 1;
    } 
    return compare;
}

compareTo – tipp a megjegyzésre

Set

Set – példa

Set<Person> set = new HashSet<Person>(); 
set.add(new Person("Aladar", 2000));

// Egy egyenlő objektum már van bent, nem csinál semmit
set.add(new Person("Aladar", 2000));

System.out.println(set.size()); // 1

// A törlés is equals alapján történik
set.remove(new Person("Aladar", 2000));

System.out.println(set.size()); // 0

Map

Map – példa

Map<String, Person> map =
    new HashMap<String, Person>(); 

Person aladar = new Person("Aladar", 2000);
Person balazs = new Person("Balazs", 1999);

map.put("a", aladar);
map.put("b", aladar); // Oké

System.out.println(map.size()); // 2

map.put("b", balazs); // Felülírjuk

System.out.println(aladar == map.get("a")); // true

System.out.println(aladar == map.get("b")); // false
System.out.println(balazs == map.get("b")); // true

System.out.println(map.get("c")); // null
// Nem létező indexre null-t ad vissza

Absztrakt osztály

Absztrakt osztály – példa

abstract class Rectangle {
    private double a;
    
    public Rectangle(double a) {
        this.a = a;
    }
    
    public double getA() { return a; }

    public abstract double getB();
    
    public double getArea() {
        return getA() * getB();
    }
}       

Absztrakt osztály – példa – 2.

class GeneralRectangle extends Rectangle {
    private double b;
    
    public GeneralRectangle(double a, double b) {
        super(a);
        this.b = b;
    }
    
    @Override
    public double getB() { return b; }
}

class Square extends Rectangle {
    public Square(double a) {
        super(a);
    }
    
    @Override
    public double getB() { return getA(); }
}

Kivételhierarchia

Saját kivételek

class UnnamedPersonException extends Exception {
}

class EmptyStackException extends RuntimeException {
    EmptyStackException() {
        super("The accessed stack is empty," +
            "no element can be retrieved.");
    }
}

Kivételhierarchia – catch és throws

RuntimeException

Sablonok bővebben, beágyazott és névtelen osztályok, lambda-kifejezések, clone

Generikus típus - ismétlés

public class Box {
    private Object object;

    public void set(Object object)
    {
        this.object = object;
    }

    public Object get() {
        return object;
    }
}

Problémák:

Megoldás: fordítási idejű ellenőrzés - generikusok

public class Box<T> {
    // a T a "Type" rövidítése
    private T t;

    public void set(T t) { this.t = t; }

    public T get() { return t; }
}

//használat:
Box<Integer> integerBox = new Box<>();

Generikus metódusok

public class Util {
    public static<K,V> boolean compare(Pair<K,V> p1 , Pair<K,V> p2) {
        return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());
    }
}

Megszorítások típusparaméterekre

public interface Comparable<T> {
    public int compareTo(T o );
}

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray) {
        if(e.compareTo(elem) > 0) {
            ++count;
        }
    }
    return count;
}

Generics - praktikus szabályok

interface Edge {
    int getSource();
    int getTarget();
}

abstract class Graph<E extends Edge> {...}
class SparseGraph<E extends Edge> extends Graph <E > {...}

Beágyazott osztályok

Névtelen osztályok

Lambda-kifejezések

Lambda-kifejezések - szintaktika

Lambda-kifejezések - példák

p -> p. getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25

ha blokkot használunk szükség van a returnhasználatára

p -> {
    return p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25;
}

Lambda-kifejezések - Comparator

Listák rendezése: java.util.Collections.sort statikus metódussal:

  1. Comparable<T> interfészt megvalósító T osztályokat tároló listák:
  2. Listákra általában:

Clone

Sekély másolás/shallow copy

Mi történik mikor klónozunk?

//..
public static void main(String [] x) throws CloneNotSupportedException {
CloneTrial ct = new CloneTrial();
CloneTrial ct1 = ct.clone();
ct.xyz.x = 1;
System.out.println(ct1.xyz.x );
}
// OUTPUT : 1