Zapoznamy się tu z nowymi
elementami standardowej edycji Javy w wersji 1.5 (J2SE wersja
5). Więcej informacji na temat takich elementów Javy 1.5 jak
typy sparametryzowane i adnotacje można znaleźć w następnych
dwóch wykładach. Ciekawy pakiet java.util.concurrent
omawiany jest w wykładach 8 i 9. W wykładach końcowych (11 i 14) będzie
mowa o nowościach edycji "enterprise" - J2EE w wersji 5.
public class AutoBoxing { private int intField; public AutoBoxing() { // Konwersje przy przypisaniu int x = 1; Integer a = x; int y = a; System.out.println("Konwersje przy przypisaniu: " + a + " " + y); // Konwersje przy wywołaniu metod methodInvocationConversion1(x); methodInvocationConversion2(a); // Konwersje przy zwrocie wyników y = getIntFromInteger(); a = getIntegerFromInt(); System.out.println("Konwersje przy zwrocie wyniku: " + a + " " + y); } public AutoBoxing(Integer i) { intField = i; System.out.println("W konstruktorze bezparametrowym: " + intField); } void methodInvocationConversion1(Integer p) { System.out.println("Parametr Integer, argument int " + p); } void methodInvocationConversion2(int p) { System.out.println("Parametr int, argument Integer " + p); } int getIntFromInteger() { return new Integer(2); } Integer getIntegerFromInt() { return 2; } public static void main(String[] args) { new AutoBoxing(); // Zauważmy, że konstruktor możemy wołać z arg. int lub Integer new AutoBoxing(3); new AutoBoxing(new Integer(3)); } }da w wyniku:
interface List<E> { // E jest parametrem oznaczającym typ danych // .... } class ArrayList<E> ... { ... }
List<String> lista1 = new ArrayList<String>(); List<Integee> lista2 = new ArrayList<Integer>();
lista1.add("Jan"); // Ok lista1.add(new Date()); // błąd w kompilacji; przedtem niewykrywalny.
for (Iterator<String> it = lista1.iterator(); it.hasNext(); ) { String name = it.next(); // ... tu coś robimy z name }
lista2.add(5); int n = lista2.get(1);
import java.util.*; import javax.swing.*; public class CountWords { private String testString = "ala ma kota ala i ma psa ala"; private Map<String,Integer> map = new HashMap<String,Integer>(); public CountWords() { String[] words = testString.split(" +"); // Zliczanie słów for (int i = 0; i < words.length; i++) { int n = 0; try { n = map.get(words[i]); } catch(NullPointerException exc) { System.out.println("Pierwsze zliczenie słowa: " + words[i]); } map.put(words[i], ++n); } // Wyniki StringBuilder wynik = new StringBuilder("Wyniki:\n"); for (String word : map.keySet()) { wynik.append(word).append(' ').append(map.get(word)).append('\n'); } JOptionPane.showMessageDialog(null, wynik); } public static void main(String[] args) { new CountWords(); } }Tu dzięki zastosowaniu sparametryzowanej mapy oraz autoboxingu kod jest niezwykle prosty, czytelny, krótki.
public interface Iterable<E> { Iterator<E> iterator(); }implementują klasy kolekcyjne, możemy też sami go implementować we własnych klasach czyniąc ich obiekty "iterowalnymi" za pomocą "for-each".
import java.util.*; class FromTo implements Iterable<Calendar> { private Calendar from = Calendar.getInstance(), to = Calendar.getInstance(); public FromTo(Calendar f, Calendar t) { from.setTime(f.getTime()); to.setTime(t.getTime()); } public CalendarIterator iterator() { return new CalendarIterator(); } private class CalendarIterator implements Iterator { Calendar current = Calendar.getInstance(), next = Calendar.getInstance(); CalendarIterator() { current.setTime(from.getTime()); current.add(Calendar.DATE, -1); } public boolean hasNext() { next.setTime(current.getTime()); next.add(Calendar.DATE, 1); return next.compareTo(to) <= 0; } public Calendar next() { if (!hasNext()) throw new NoSuchElementException(); current.add(Calendar.DATE, 1); return current; } public void remove() {} } } public class ForEach { public ForEach() { String[] names = { "Ala", "Asia", "Janek" }; List<String> list = Arrays.asList(names); for (String name : names) System.out.println(name); for (String name : list) // to jest String, ale bez generics byłby Object System.out.println(name + " - długość " + name.length()); Calendar from = Calendar.getInstance(); Calendar to = Calendar.getInstance(); to.add(Calendar.DAY_OF_MONTH, 5); FromTo timeInterval = new FromTo(from, to); for (Calendar day : timeInterval) { System.out.println(day.getTime()); } } public static void main(String[] args) { new ForEach(); } }Warto zwrócić uwagę na to, że dla zastosowania for-each bez rzutowania ważne jest by klasa implementowała interfejs Iterable z konkretnym parametrem typu - tu Iterable<Calendar>.
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class StaticImports extends JFrame { public StaticImports() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Color[] colors = { Color.RED, Color.BLUE, Color.GREEN }; getContentPane().setLayout(new FlowLayout()); for (int i=0; i<colors.length; i++) { JButton b = new JButton("Przycisk"); b.setForeground(colors[i]); b.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Akcja"); } }); getContentPane().add(b); } pack(); show(); try { Thread.sleep(2000); } catch(Exception exc) {} SwingUtilities.invokeLater( new Runnable() { public void run() { getContentPane().setBackground(Color.YELLOW); } }); double d = Math.max(2.1, 2.3); System.out.println(d); d = Math.pow(2,7); System.out.println(d); } public static void main(String[] args) { new StaticImports(); } }
import java.awt.*; import java.awt.event.*; import javax.swing.*; import static java.awt.Color.*; import static javax.swing.JFrame.*; import static java.lang.System.out; import static java.lang.Thread.sleep; import static javax.swing.SwingUtilities.*; import static java.lang.Math.*; public class StaticImportsWork extends JFrame { public StaticImportsWork() { setDefaultCloseOperation(EXIT_ON_CLOSE); // łatwiej! Color[] colors = { RED, BLUE, GREEN }; // łatwiej! setLayout(new FlowLayout()); // bez contentPane ! for (Color c : colors) { // nowe for JButton b = new JButton("Przycisk"); b.setForeground(c); b.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { out.println("Akcja"); // łatwiej } }); add(b); // bez contentPane ! } pack(); show(); try { sleep(500); } catch(Exception exc) {} // łatwiej invokeLater( new Runnable() { // łatwiej public void run() { getContentPane().setBackground(YELLOW); // łatwiej } }); // Również szczególnie użyteczne przy operacjach matematycznych double d = max(2.1, 2.3); out.println(d); d = pow(2,7); out.println(d); } public static void main(String[] args) { new StaticImportsWork(); } }
import java.awt.*; import java.awt.event.*; import java.beans.*; import javax.swing.*; import static java.awt.Color.*; import static java.lang.Thread.sleep; import static java.lang.System.out; public class Varargs extends JFrame { JTextArea report = new JTextArea(25, 40); public Varargs() { setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); report.setBorder(BorderFactory.createTitledBorder("Raport")); add(new JScrollPane(report)); JPanel p = new JPanel(); final JLabel lab = new JLabel("Label"); lab.setOpaque(true); p.add(lab); final JButton b1 = new JButton("Kolory 1"); b1.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { setColor(RED, b1); } }); p.add(b1); final JButton b2 = new JButton("Kolory 2"); b2.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { setColor(GREEN, b2, lab); } }); p.add(b2); final JButton b3 = new JButton("Kolory 3"); b3.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { setColor(YELLOW, b1, b2, b3, lab); } }); p.add(b3); add(p, "North"); pack(); setVisible(true); } private void setColor(final Color color, final Component ... comps) { report.append("Liczba przekazanych komponentów: " + comps.length +'\n'); report.append("Szerokość pierwszego komponentu: " + comps[0].getWidth() + '\n'); report.append("Szerokość ostatniego komponentu: " + comps[comps.length-1].getWidth() + '\n'); for (Component c : comps) c.setBackground(color); met(1, 3, 5); } private void met(int ... p) { for(int v : p) report.append(v + " "); } public static void main(String[] args) { new Varargs(); } }
public class ActionSet { public void dodaj() { show("Dodaj"); } public void usuń() { show("Usuń"); } public void zastąp() { show("Zastąp"); } public void szukaj() { show("Szukaj"); } public void otwórz() { show("Otwórz"); } private void show(String string) { JOptionPane.showMessageDialog(null, string); } }Opcje dla użytkownika będą przedstawione w menu kontekstowym, otwieranym na przycisku. Z tego menu może on wybrać (wielokrotnie i różnie w trakcie działania programu) co konkretnie ma się stać, jeśli przyciśnie ten przycisk.
import java.lang.reflect.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ReflectionTest extends JFrame implements ActionListener { Method currAction = null; // bieżąca metoda obsługi Class actionClass = null; // klasa obsługi Object actionObject = null; // obiekt obsługi JPopupMenu popUp = null; // menu kontekstowe z wyborem obsługi JButton b; public ReflectionTest() { super("Test refleksji"); try { actionClass = Class.forName("demo6.ActionSet"); actionObject = actionClass.newInstance(); } catch (Exception exc) { throw new RuntimeException("Wadliwa klasa obsługi"); } popUp = new JPopupMenu(); createMenuItems(); b = new JButton("Użyj prawego klawisza myszki, by ustalić akcję"); b.setFont(new Font("Dialog", Font.BOLD, 24)); b.addActionListener(this); b.setComponentPopupMenu(popUp); // ułatwienie z popup!!! setLayout(new FlowLayout()); add(b); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); pack(); setLocationRelativeTo(null); setVisible(true); } void createMenuItems() { Method mets[] = null; try { mets = actionClass.getMethods(); } catch (Exception exc) { throw new RuntimeException("Niedostępna info o metodach klasy obsługi"); } for (Method m : mets) { if (m.getDeclaringClass() == actionClass) { String name = m.getName(); JMenuItem mi = new JMenuItem(name); mi.addActionListener(this); popUp.add(mi); } } } void setCurrentAction(String action) { try { currAction = actionClass.getMethod(action); // zm. liczba arg.!!! b.setText("Teraz akcją jest: " + currAction.getName() + " - kliknij!"); } catch (Exception exc) { throw new RuntimeException("Nieznana metoda obsługi"); } } public void actionPerformed(ActionEvent e) { Object src = e.getSource(); if (src instanceof JMenuItem) setCurrentAction(((JMenuItem) src).getText()); else { try { currAction.invoke(actionObject); // zmienna liczba arg. !!! } catch (Exception exc) { JOptionPane.showMessageDialog(null, "Akcja na przycisku nieustalona!"); } } } public static void main(String args[]) { new ReflectionTest(); } }
public enum DayOfWeek { PONIEDZIAŁEK, WTOREK, SRODA, CZWARTEK, PIĄTEK, SOBOTA, NIEDZIELA } public enum Weather { POCHMURNO, SŁONECZNIE, DESZCZOWO } public enum Temperature { ZIMNO, CIEPŁO }
class DayWeather { private DayOfWeek day; private Weather weather; private Temperature temp; public DayWeather( DayOfWeek d, Weather w, Temperature t) { day = d; weather = w; temp = t; } public String toString() { return "W " + day + " było " + weather + " i " + temp; } public Weather getWeather() { return weather; } } public class Enums { // Przestrzenie nazw są rozdzielone public enum Szukaj { CIEPŁO, ZIMNO }; public Enums() { // Łatwy sposób iterowania po elementach enumeracji for (DayOfWeek d : DayOfWeek.values()) System.out.println(d); Szukaj stan = Szukaj.CIEPŁO; // Nie można się pomylić - błąd w kompilacji: //DayWeather dw = new DayWeather(DayOfWeek.CZWARTEK, Weather.SŁONECZNIE, // stan); // można używać w switchu // przy czym ze względu na znany typ zmiennej etykiety nie muszą // być kwalifikowane nazwą klasy enum switch(stan) { case ZIMNO : System.out.println("Jest zimno"); break; case CIEPŁO : System.out.println("Jest ciepło"); break; } DayWeather dw1 = new DayWeather(DayOfWeek.CZWARTEK, Weather.SŁONECZNIE, Temperature.CIEPŁO); // Naturalny wydruk System.out.println(dw1); DayWeather dw2 = new DayWeather(DayOfWeek.WTOREK, Weather.DESZCZOWO, Temperature.CIEPŁO); // Elementy enumeracji są obiektami-singletonami // możemy zatem używać operatora == if (dw2.getWeather() == Weather.DESZCZOWO) System.out.println("Był deszcz"); else System.out.println("nie padało"); } public static void main(String[] args) { new Enums(); } }Wynik działania programu:
package kiosk; public enum Gazety { Głos(1), Polityka(4.5), Gazeta(2.5); Gazety(double p) { price = p; } public double getPrice() { return price; } private final double price; }
package kiosk; import java.util.*; import static kiosk.Gazety.*; // musi być nazwany pakiet! import static java.lang.System.out; public class Kiosk { private EnumMap<Gazety, Integer> map = new EnumMap<Gazety, Integer>(Gazety.class); public Kiosk() { supply(Głos, 20); supply(Polityka, 20); supply(Gazeta, 20); // co jest w kiosku: // Jak łatwo i elegancko!!! for (Gazety g : map.keySet()) out.println(g + " - liczba egzemplarzy " + map.get(g)); // Sprzedajemy trochę double income = 0; income += sale(Głos, 2); income += sale(Polityka, 10); income += sale(Gazeta, 5); income += sale(Głos, 2); // Teraz w kiosku zostało for (Gazety g : map.keySet()) out.println(g + " - liczba egzemplarzy " + map.get(g)); // a uzyskany dochód ze sprzedaży out.println("Dochód: " + income); } /** * Dostawa q sztuk gazety g * @param g - konkretna gazeta * @param q - liczba sztuk w dostawie */ public void supply(Gazety g, int q) { if (map.containsKey(g)) q += map.get(g); map.put(g, q); } /** * sprzedaż q sztuk gazety g * @param g - sprzedawana gazeta * @param q - liczba sprzedanych sztuk * @return wartość transakcji */ public double sale(Gazety g, int q) { if (!map.containsKey(g)) return 0; int n = map.get(g); if (q > n) q = n; map.put(g, n-q); return q*g.getPrice(); } public static void main(String[] args) { Kiosk kiosk = new Kiosk(); } }
package kiosk; public enum Gazety { // W konstruktorze użyjemy dwóch parametrów // Ze stałymi wyliczenia zwiążemy przedefiniowane metody toString // tak, by wydruk był ładniejszy nieco Głos(0.75, 1) { public String toString() { return "Tygodnik \"Głos\""; } }, Polityka(4, 4.5) { public String toString() { return "Tygodnik \"Polityka\""; } }, Gazeta(2, 2.5) { public String toString() { return "\"Gazeta Wyborcza\""; } }; Gazety(double wp, double rp) { wholesalePrice = wp; retailPrice = rp; } public double getRetailPrice() { return retailPrice; } public double getWholesalePrice() { return wholesalePrice; } private final double wholesalePrice; private final double retailPrice; }
package kiosk; import java.util.*; // Dosyć funkcjonalna enumeracja // opisuje możliwe transakcje (dostawa, sprzedaż gazet) // a zarazem prowwadzi rejestr magazynu i rejestr sprzedanych gazet public enum Transaction { // Elementy wyliczenia (konkretne operacje) // Wiązemy z nimi ciała podklas, w których // implementujemy metodę perform, // która jest zadeklarowana na końcu jako abstrakcyjna // Uwaga: w klasach enum elementy wyliczenia zdaje się winny // poprzedzać wszelkie rozszerzenia funkcjonalności SUPPLY { public void perform(Gazety g, int n) { if (volume.containsKey(g)) n += volume.get(g); volume.put(g, n); } }, SALE { public void perform(Gazety g, int n) { if (!volume.containsKey(g)) return; int k = volume.get(g); if (n > k) n = k; volume.put(g, k-n); sold.put(g, n); } }; // Gazety - stan magazynowy private static final EnumMap<Gazety, Integer> volume = new EnumMap<Gazety, Integer>(Gazety.class); // Gazety - sprzedane private static final EnumMap<Gazety, Integer> sold = new EnumMap<Gazety, Integer>(Gazety.class); public static EnumMap<Gazety, Integer> getVolume() { return volume; } public static EnumMap<Gazety, Integer> getSold() { return sold; } // Metoda perform musi być zsdeklarowana jako abstrakcyjna // ona własnie jest w różny sposób implemetowana w ciałach podklas // przypisanych stałym wyliczenia public abstract void perform(Gazety g, int n); }No i nowa klasa Kiosk, która w pełni korzysta z dobrodziejstw obu enumeracji i w łatwy sposób uzyskuje sporą funkcjonalnośc pod względem obliczeniowym i prezentacyjnym.
package kiosk; import java.util.*; import static kiosk.Gazety.*; import static kiosk.Transaction.*; import static java.lang.System.out; public class Kiosk { public Kiosk() { // Sprowadzamy gazety // możemy użyć dalej zdefiniowanej metody trans (może coś jeszcze będzie robić) trans(SUPPLY, Głos, 20); trans(SUPPLY, Polityka, 20); trans(SUPPLY, Gazeta, 20); // ale możemy też pisać tak: SUPPLY.perform(Gazeta, 10); SUPPLY.perform(Polityka, 10); // co jest w kiosku i ile wydano na sprowadzenie gazet: out.println("Po dostawie w kiosku są następujące gazety:"); double cost = 0; for (Gazety g : getVolume().keySet()) { int n = getVolume().get(g); cost += g.getWholesalePrice() * n; out.println(g + " - liczba egzemplarzy " + n ); } out.println("Wydano: " + cost); // Sprzedajemy trochę SALE.perform(Polityka, 15); SALE.perform(Głos, 10); SALE.perform(Gazeta, 20); // Co sprzedano i ile uzyskano? out.println("Sprzedano gazety: "); double income = 0; for (Gazety g : getSold().keySet()) { int n = getSold().get(g); income += g.getRetailPrice() * n; out.println(g + " - liczba egzemplarzy " + n ); } out.println("Dochód " + income); out.println("Zarobek : " + (income - cost)); // Inny sposób wyciągania danych out.println("Zostały do sprzedaży:"); for(Gazety g : Gazety.values()) out.println(g + " - liczba egzemplarzy: " + getVolume().get(g)); } /** * Ew. można taką metodę sobie dodac * Transakcja - zakup gazet do kiosku lub ich sprzedaż * @param t - rodzaj transakcji (SUPPLY lub SALE) * @param g - jaka gazeta * @param n - ile sztuk */ public void trans(Transaction t, Gazety g, int n) { t.perform(g, n); } public static void main(String[] args) { Kiosk kiosk = new Kiosk(); } }Wynik działania programu:
File, String, OutputStream, obiekty klas implementujących interfejs Appendable, czyli:
import java.util.*; class Employee { String name; double salary; Employee(String n, double s) { name = n; salary = s; } public double getSalary() { return salary; } public String toString() { return name + " " + salary; } } public class Skaner1 { String s1 = "1 2 3"; String s2 = "Jan Kowalski/1200\nA. Grabowski/1500"; public Skaner1() { Scanner scan1 = new Scanner(s1); int suma = 0; while (scan1.hasNextInt()) suma += scan1.nextInt(); System.out.println("Suma = " + suma); List<Employee> list = new ArrayList<Employee>(); Scanner scan2 = new Scanner(s2); while (scan2.hasNextLine()) { Scanner scan3 = new Scanner(scan2.nextLine()).useDelimiter("/"); String name = scan3.next(); double salary = scan3.nextDouble(); list.add(new Employee(name, salary)); } double value = 0; for (Employee emp : list) { value += emp.getSalary(); System.out.println(emp); } System.out.println("Suma zarobków: " + value); } public static void main(String[] args) { Skaner1 skaner1 = new Skaner1(); } }