Commit b99e31d7 by Patryk Czarnik

przykłady "sprzedaz"

parent 6be82c5a
...@@ -57,7 +57,7 @@ public class Collect_i_Reduce { ...@@ -57,7 +57,7 @@ public class Collect_i_Reduce {
System.out.println("4: " + wynik); System.out.println("4: " + wynik);
} }
// to tłumaczy się na taką pętlę: // to tłumaczy się na taką pętlę:
{ {
String wynik = ""; String wynik = "";
for (String s : imiona) { for (String s : imiona) {
......
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/* Dla każdego miasta występującego w pliku z danymi
oblicz sumę wartości transakcji w tym mieście.
*/
/* W tej wersji najpierw ustalamy zbiór miast bez powtórzeń,
a następnie dla każdego miasta przeglądamy wszystkie rekordy z listy i filtrujemy.
Ma to niską wydajność. Złożoność: liczba miast × licza wszystkich rekordów.
*/
public class Grupowanie0 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Set<String> miasta = new TreeSet<>();
for(Transakcja r : lista) {
miasta.add(r.miasto());
}
System.out.println(miasta);
for (String miasto : miasta) {
BigDecimal suma = BigDecimal.ZERO;
for (Transakcja r : lista) {
if(r.miasto().equals(miasto)) {
suma = suma.add(r.wartosc());
}
}
System.out.printf("%-10s : %12s%n", miasto, suma);
}
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.*;
/* W tej wersji widzimy często stosowany schemat "grupowanie z wykorzystaniem słownika.
Korzystamy z operacji dostępnych od Java 5.
*/
public class Grupowanie1 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, BigDecimal> slownik = new TreeMap<>();
for(Transakcja r : lista) {
if(slownik.containsKey(r.miasto())) {
// to jest kolejny rekord z danego miasta → do obliczonej sumy dodajemy kolejny składnik
BigDecimal suma = slownik.get(r.miasto());
slownik.put(r.miasto(), suma.add(r.wartosc()));
} else {
// to jest pierwszy rekord z danego miasta → dodajemy pierwszy wpis
slownik.put(r.miasto(), r.wartosc());
}
}
// System.out.println(slownik);
// Przeglądanie zawartości słownika jako kluczy z wartościami
// wersja "Java 5":
for (Map.Entry<String, BigDecimal> entry : slownik.entrySet()) {
System.out.printf("%-10s : %12s%n", entry.getKey(), entry.getValue());
}
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/* Operacja dostępna od Java 8: getOrDefault */
public class Grupowanie2 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, BigDecimal> slownik = new TreeMap<>();
for(Transakcja r : lista) {
BigDecimal suma = slownik.getOrDefault(r.miasto(), BigDecimal.ZERO);
slownik.put(r.miasto(), suma.add(r.wartosc()));
}
for (Map.Entry<String, BigDecimal> entry : slownik.entrySet()) {
System.out.printf("%-10s : %12s%n", entry.getKey(), entry.getValue());
}
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/* Operacja "funkcyjna" na słownikach dostępna od Java 8: merge
Jest to operacja dokładnie implementująca ten schemat, który realizujemy w naszym zadaniu.
slownik.merge(KLUCZ, WARTOŚĆ, FUNKCJA)
Jeśli pod KLUCZem jeszcze niczego nie ma, to wpisywana jest WARTOŚĆ
Jeśli pod KLUCZem jest już STARA_WARTOŚĆ, to uruchamiana jest FUNKCJA
NOWA_WARTOŚĆ := FUNKCJA(STARA_WARTOŚĆ, WARTOŚĆ)
np. jeśli funkcją jest operacja dodawania, to będzie tak:
NOWA_WARTOŚĆ := STARA_WARTOŚĆ + WARTOŚĆ
*/
public class Grupowanie3 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, BigDecimal> slownik = new TreeMap<>();
for(Transakcja r : lista) {
slownik.merge(r.miasto(), r.wartosc(), BigDecimal::add);
}
for (Map.Entry<String, BigDecimal> entry : slownik.entrySet()) {
System.out.printf("%-10s : %12s%n", entry.getKey(), entry.getValue());
}
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Grupowanie4 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
final Map<String, StatystykiDlaMiasta> mapa = new TreeMap<>();
for (Transakcja transakcja : lista) {
final String miasto = transakcja.miasto();
StatystykiDlaMiasta statystyki = mapa.get(miasto);
if (statystyki == null) {
statystyki = new StatystykiDlaMiasta(miasto);
mapa.put(miasto, statystyki);
}
statystyki.update(transakcja);
// nie trzeba robić put, bo modyfikuję ten obiekt, który już jest w słowniku
}
for (StatystykiDlaMiasta statystykiZMiasta : mapa.values()) {
System.out.println(statystykiZMiasta);
}
}
// Klasa zgnieżdżona - tylko dla przykładu.
// Równie dobrze mógłbym tę klase zdefiniować w osobnym pliku.
// Obiekt tej klasy przechowuje statystyki job
private static class StatystykiDlaMiasta {
final String miasto;
int count = 0;
BigDecimal sum = BigDecimal.ZERO;
BigDecimal min = null;
BigDecimal max = null;
StatystykiDlaMiasta(String miasto) {
this.miasto = miasto;
}
void update(Transakcja transakcja) {
BigDecimal wartosc = transakcja.wartosc();
count++;
sum = sum.add(wartosc);
if (min == null || wartosc.compareTo(min) < 0) {
min = wartosc;
}
if (max == null || wartosc.compareTo(max) > 0) {
max = wartosc;
}
}
BigDecimal avg() {
return sum.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_EVEN);
}
@Override
public String toString() {
return "jobTitle=" + miasto + ", count=" + count + ", sum=" + sum + ", min=" + min + ", max="
+ max + ", avg=" + avg();
}
}
}
package sprzedaz;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie5 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, List<Transakcja>> grupy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto));
// Tak wywołany kolektor groupingBy zwraca słownik, w którym dla każdej wartości klucz (czyli miasta)
// zapisana jest lista wszystkich obiektów należących do tej grupy (czyli rekordów z tego miasta).
// Tutaj też zoabczymy przeglądanie słownika z sposób oparty o wyrażenia lambda, od Java 8
grupy.forEach((miasto, rekordy) -> {
System.out.println("Miasto " + miasto + ", liczba transakcji: " + rekordy.size());
rekordy.forEach(r -> System.out.println(" * " + r.towar() + " za " + r.wartosc()));
System.out.println();
});
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie6a {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, BigDecimal> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12s%n", miasto, suma));
}
}
package sprzedaz;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie6b {
public static void main(String[] args) throws IOException {
List<Transakcja> lista = MaszynaWczytujaca2.wczytajCalyPlik();
Map<String, BigDecimal> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12s%n", miasto, suma));
}
}
package sprzedaz;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie6c {
public static void main(String[] args) throws IOException {
Map<String, BigDecimal> sumy = MaszynaWczytujaca2.dajStrumien(false)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12s%n", miasto, suma));
}
}
package sprzedaz;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie6d {
public static void main(String[] args) throws IOException {
Map<String, BigDecimal> sumy = MaszynaWczytujaca2.dajStrumien(true)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12s%n", miasto, suma));
}
}
package sprzedaz;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Grupowanie7 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
// W tej wersji do kolektora groupingBy przekazujemy kolejny parametr,
// też kolektor mówiący "co robić każdą grupą".
Map<String, Double> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.summingDouble(Transakcja::wartoscDouble)));
// sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12s%n", miasto, suma));
sumy.forEach((miasto, suma) -> System.out.printf("%-10s : %12.2f%n", miasto, suma));
}
}
package sprzedaz;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// Wersja z liczeniem statystyk, czyli coint, sum, avg, min i max jednocześnie
public class Grupowanie8 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
Map<String, DoubleSummaryStatistics> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.summarizingDouble(Transakcja::wartoscDouble)));
sumy.forEach((miasto, stats) -> System.out.printf("%-10s : %s%n", miasto, stats));
}
}
package sprzedaz;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MaszynaWczytujaca1 {
public static List<Transakcja> wczytaj() {
return wczytaj("sprzedaz.csv");
}
public static List<Transakcja> wczytaj(String sciezka) {
return wczytaj(new File(sciezka));
}
public static List<Transakcja> wczytaj(File plik) {
List<Transakcja> lista = new ArrayList<>();
try(Scanner scanner= new Scanner(plik)) {
scanner.nextLine();
while(scanner.hasNextLine()) {
String linia = scanner.nextLine();
String[] t = linia.split(",", -1);
Transakcja transakcja = new Transakcja(LocalDate.parse(t[0]),
t[1], t[2], t[3],t[4],
new BigDecimal(t[5]), Integer.parseInt(t[6]));
lista.add(transakcja);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lista;
}
}
package sprzedaz;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
/* Ta wersja klasy wczytującej dane z pliku stosuje technikę "puli obiektów",
* czyli w kolejnych rekordach wykorzystuje jako wartości pól te same obiekty,
* które zostały użyte wcześniej, jeśli wartości pól są jednakowe.
* Dla klasy `String` korzystam z istniejącej metody `intern`, która
* jest realizowana bezpośrednio przez JVM. Natomaist dla klas `BigDecimal` oraz `LocalDate`
* tworzę własną implementację tego mechanizmu opartą o słowniki.
* Ta technika służy przede wszystkim oszczędzaniu pamięci,
* może zwrócić się czasowo, jeśli dane po wczytaniu będą później intensywnie używane chociażby w porównaniach,
* jest poprawna w przypadku klas niemutowalnych.
*/
public class MaszynaWczytujaca2 {
private static final String DOMYSLNY_PLIK = "sprzedaz.csv";
private final Map<String, LocalDate> pulaDat = new ConcurrentHashMap<>();
private final Map<String, BigDecimal> pulaCen = new ConcurrentHashMap<>();
public Transakcja wczytajJedenRekord(String linia) {
String[] pola = linia.split(",");
int sztuk = Integer.parseInt(pola[6]);
LocalDate data = pulaDat.computeIfAbsent(pola[0], LocalDate::parse);
BigDecimal cena = pulaCen.computeIfAbsent(pola[5], BigDecimal::new);
String miasto = pola[1].intern();
String sklep = pola[2].intern();
String kategoria = pola[3].intern();
String towar = pola[4].intern();
return new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
}
public static List<Transakcja> wczytajCalyPlik(File plik) {
MaszynaWczytujaca2 maszynaWczytujaca = new MaszynaWczytujaca2();
List<Transakcja> lista = new ArrayList<>();
try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
String linia = reader.readLine(); // ignoruję nagłówki
while((linia = reader.readLine()) != null) {
Transakcja transakcja = maszynaWczytujaca.wczytajJedenRekord(linia);
lista.add(transakcja);
}
return lista;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static List<Transakcja> wczytajCalyPlik(String plik) {
return wczytajCalyPlik(new File(plik));
}
public static List<Transakcja> wczytajCalyPlik() throws IOException {
return wczytajCalyPlik(DOMYSLNY_PLIK);
}
public static Stream<Transakcja> dajStrumien(Path plik, boolean parallel) {
try {
MaszynaWczytujaca2 maszynaWczytujaca = new MaszynaWczytujaca2();
Stream<String> s = Files.lines(plik).skip(1);
return (parallel ? s.parallel() : s)
.map(maszynaWczytujaca::wczytajJedenRekord);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static Stream<Transakcja> dajStrumien(String plik, boolean parallel) {
return dajStrumien(Paths.get(plik), parallel);
}
public static Stream<Transakcja> dajStrumien(boolean parallel) {
return dajStrumien(DOMYSLNY_PLIK, parallel);
}
}
package sprzedaz;
import javax.swing.*;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class Opt1 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
String miasto = JOptionPane.showInputDialog("Podaj miasto");
Optional<Transakcja> wynik = lista.stream()
.filter(r -> r.miasto().equalsIgnoreCase(miasto))
.max(Comparator.comparing(Transakcja::wartosc));
System.out.println("Obiekt wynikowy: " + wynik);
// sposoby obsługi Optionala
// klasyczny if
if(wynik.isPresent()) {
Transakcja r = wynik.get();
JOptionPane.showMessageDialog(null,
"Transakcja z dnia " + r.data() + " o wartości " + r.wartosc()
+ "\n" + r.sztuk() + " sztuk towaru " + r.towar());
} else {
JOptionPane.showMessageDialog(null, "Nie ma transakcji w mieście " + miasto,
"Brak danych", JOptionPane.ERROR_MESSAGE);
}
}
}
package sprzedaz;
import javax.swing.*;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class Opt2 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
String miasto = JOptionPane.showInputDialog("Podaj miasto");
// Tutaj operacja max zwraca Optional i od razu stosujemy operację ifPresent
// Kod podany w ifPresent wykona się tylko jeśli wynik został znaleziony
// lista.stream()
// .filter(r -> r.miasto().equalsIgnoreCase(miasto))
// .max(Comparator.comparing(Rekord::wartosc))
// .ifPresent(r -> JOptionPane.showMessageDialog(null,
// "Transakcja z dnia " + r.data() + " o wartości " + r.wartosc()
// + "\n" + r.sztuk() + " sztuk towaru " + r.towar()));
lista.stream()
.filter(r -> r.miasto().equalsIgnoreCase(miasto))
.max(Comparator.comparing(Transakcja::wartosc))
.ifPresentOrElse(
r -> JOptionPane.showMessageDialog(null,
"Transakcja z dnia " + r.data() + " o wartości " + r.wartosc()
+ "\n" + r.sztuk() + " sztuk towaru " + r.towar())
, () -> JOptionPane.showMessageDialog(null, "Nie ma transakcji w mieście " + miasto,
"Brak danych", JOptionPane.ERROR_MESSAGE)
);
}
}
package sprzedaz;
import javax.swing.*;
import java.util.Comparator;
import java.util.List;
public class Opt3 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
String miasto = JOptionPane.showInputDialog("Podaj miasto");
// Operacja map wykonana na obiekcie Optional zwraca w wyniku Optional
// który jest pusty, jeśli ten pierwszy był pusty, a zawiera wynik funkcji mapującej, jeśli pierwszy zawierał dane.
// W tym przypadku z Optional<Rekord> powstaje Optional<String>
// Operacja orElse odczytuje wartość, która jest w Optionalu (w tym przypadku string "Transakcja z dnia....")
// a zwraca podaną wartość domyślną, jeśli w Optionalu nie było niczego.
// Tak pisany orElse ma sens wtedy, gdy wartość domyślna jest zawsze taka sama (nie wymaga obliczeń).
// Gdy uzyskanie tej wartości wymaga obliczeń, zalecane jest stosowanie orElseGet (zob. następna wersja)
String tekst = lista.stream()
.filter(r -> r.miasto().equalsIgnoreCase(miasto))
.max(Comparator.comparing(Transakcja::wartosc))
.map(r -> "Transakcja z dnia " + r.data() + " o wartości " + r.wartosc()
+ "\n" + r.sztuk() + " sztuk towaru " + r.towar())
.orElse("Nie znaleziono rekordów w podanym mieście");
JOptionPane.showMessageDialog(null, tekst);
}
}
package sprzedaz;
import javax.swing.*;
import java.util.Comparator;
import java.util.List;
public class Opt4 {
public static void main(String[] args) {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj();
String miasto = JOptionPane.showInputDialog("Podaj miasto");
// orElseGet(() -> wzrór na wynik)
// wykona obliczenie tworzące wynik tylko wtedy i dopiero wtedy, gdy jest to potrzebne
String tekst = lista.stream()
.filter(r -> r.miasto().equalsIgnoreCase(miasto))
.max(Comparator.comparing(Transakcja::wartosc))
.map(r -> "Transakcja z dnia " + r.data() + " o wartości " + r.wartosc()
+ "\n" + r.sztuk() + " sztuk towaru " + r.towar())
.orElseGet(() -> "Nie znaleziono rekordów w mieście " + miasto);
JOptionPane.showMessageDialog(null, tekst);
}
}
package sprzedaz;
import java.util.List;
public class P0_WypiszObiekty {
public static void main(String[] args) {
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
System.out.println("Liczba transakcji: " + transakcje.size());
for(Transakcja transakcja : transakcje) {
System.out.println(transakcja);
}
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.time.LocalDate;
public class PrzykladyUzyciaRekordu {
public static void main(String[] args) {
Transakcja transakcja = new Transakcja(LocalDate.now(), "Mszczonów", "Kebabik u Zbyszka",
"jedzenie", "kebab rollo", new BigDecimal("16.00"), 5);
System.out.println(transakcja);
// zauważmy, że nie rekord.towar ani nie rekord.getTowar()
System.out.println(transakcja.towar() + " kosztuje " + transakcja.cena());
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Funkcyjnie1 {
// W tej wersji obliczamy sumę jako BigDecimal, funkcyjnie, wykorzystując tylko dostęp do pól rekordu.
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
BigDecimal suma = transakcje.stream()
.filter(tr -> tr.miasto().equalsIgnoreCase(miasto))
.map(tr -> tr.cena().multiply(BigDecimal.valueOf(tr.sztuk())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Funkcyjnie2 {
// W tej wersji obliczamy sumę jako BigDecimal, funkcyjnie, wykorzystując metodę wartosc().
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
BigDecimal suma = transakcje.stream()
.filter(tr -> tr.miasto().equalsIgnoreCase(miasto))
.map(Transakcja::wartosc)
.reduce(BigDecimal.ZERO, BigDecimal::add);
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Funkcyjnie3 {
// Użytkownik wprowadza nazwę miasta, a program oblicza sumę wartości transacji z tego miasta.
// W tej wersji stosujemy strumienie i podejście "funkcyjne".
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
double suma = MaszynaWczytujaca2.dajStrumien(false)
.filter(tr -> tr.miasto().equalsIgnoreCase(miasto))
.mapToDouble(Transakcja::wartoscDouble)
.sum();
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Imperatywnie1 {
// Użytkownik wprowadza nazwę miasta, a program oblicza sumę wartości transacji z tego miasta.
// W tej wersji stosujemy zwykłe pętle i ify,
// a sumę liczymy jako BigDecimal, wykorzystując tylko dostęp do pól w rekordach.
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
BigDecimal suma = BigDecimal.ZERO;
for(Transakcja tr : transakcje) {
if(tr.miasto().equalsIgnoreCase(miasto)) {
suma = suma.add(tr.cena().multiply(BigDecimal.valueOf(tr.sztuk())));
}
}
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Imperatywnie2 {
// Użytkownik wprowadza nazwę miasta, a program oblicza sumę wartości transacji z tego miasta.
// W tej wersji stosujemy zwykłe pętle i ify,
// a sumę liczymy jako BigDecimal, wykorzystując pomocniczą metodę wartosc() zdefiniowaną w rekordzie.
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
BigDecimal suma = BigDecimal.ZERO;
for(Transakcja tr : transakcje) {
if(tr.miasto().equalsIgnoreCase(miasto)) {
suma = suma.add(tr.wartosc());
}
}
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import java.util.List;
import javax.swing.JOptionPane;
public class SumaJednegoMiasta_Imperatywnie3 {
// Użytkownik wprowadza nazwę miasta, a program oblicza sumę wartości transacji z tego miasta.
// W tej wersji stosujemy zwykłe pętle i ify,
// a sumę liczymy jako double.
public static void main(String[] args) {
String miasto = JOptionPane.showInputDialog("Podaj miasto:");
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
double suma = 0;
for(Transakcja tr : transakcje) {
if(tr.miasto().equalsIgnoreCase(miasto)) {
suma += tr.wartoscDouble();
}
}
JOptionPane.showMessageDialog(null, "Suma: " + suma);
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.util.List;
public class SumaWszystkichTransakcji {
public static void main(String[] args) {
List<Transakcja> transakcje = MaszynaWczytujaca1.wczytaj();
BigDecimal suma = BigDecimal.ZERO;
for(Transakcja tr : transakcje) {
suma = suma.add(tr.wartosc());
}
System.out.println("Suma wszystkich transakcji: " + suma);
}
}
package sprzedaz;
import java.math.BigDecimal;
import java.time.LocalDate;
/* Record to taka specjalna wersja klasy (podobnie jak enum jest specjalną wersją klasy w języku Java),
która zawiera rzeczy generowane automatycnzie na podstawie parametrów podanych w nawiasach.
Automatycznie tworzone są:
- pola private final
- konstruktor z takimi parametrami
- metody dostępowe służące do odczytu. Nie mają one w nazwie "get", tylko nazywają się tak samo jak pola
- toString, equals i hashCode (przypominające standardowe implementacje generowane przez IDE)
*/
public record Transakcja(
LocalDate data,
String miasto,
String sklep,
String kategoria,
String towar,
BigDecimal cena,
int sztuk) {
// W rekordach można definiować dodatkowe metody. Duży sens mają takie, które zwracają wyniki obliczone na podstawie wartości pól
public BigDecimal wartosc() {
return cena.multiply(BigDecimal.valueOf(sztuk));
}
public double wartoscDouble() {
return wartosc().doubleValue();
}
public int rok() {
return data.getYear();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.Transakcja;
// wersja specjalnie najwolniejsza
public class CzytajILicz1 {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
List<Transakcja> lista = WczytajSprzedaz1.wczytaj(plik);
Map<String, BigDecimal> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz1::calaRobota);
Pomiary.wypiszPamiec();
System.out.println("gc...");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* W tej wersji dane są najpierw czytane do pamięci (ArrayList), a dopiero potem przetwarzane. */
public class CzytajILicz2 {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
List<Transakcja> lista = MaszynaWczytujaca2.wczytajCalyPlik(plik);
Map<String, BigDecimal> sumy = lista.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz2::calaRobota);
Pomiary.wypiszPamiec();
System.out.println("gc...");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* W tej wersji dane są czytane stumieniowo (Files.lines) i od razu przetwarzane. */
public class CzytajILicz3 {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
MaszynaWczytujaca2 maszynaWczytujaca = new MaszynaWczytujaca2();
Map<String, BigDecimal> sumy = Files.lines(plik.toPath())
.skip(1)
.map(maszynaWczytujaca::wczytajJedenRekord)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumy.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz3::calaRobota);
Pomiary.wypiszPamiec();
System.out.println("gc...");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* W tej wersji dane są czytane stumieniowo (Files.lines) i od razu przetwarzane.
* Strumień zrównoleglony - działa szybciej
*/
public class CzytajILicz4 {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
MaszynaWczytujaca2 maszynaWczytujaca = new MaszynaWczytujaca2();
Map<String, BigDecimal> sumyDouble = Files.lines(plik.toPath())
.skip(1)
.parallel()
.map(maszynaWczytujaca::wczytajJedenRekord)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumyDouble.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz4::calaRobota);
Pomiary.wypiszPamiec();
System.out.println("gc...");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.math.BigDecimal;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca1;
import sprzedaz.Transakcja;
/* Korzystamy z przygotowanej metody w MaszynaWczytujaca1 - wersja z listą */
public class CzytajILicz5a {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
Map<String, BigDecimal> sumyDouble = MaszynaWczytujaca1.wczytaj(plik)
.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumyDouble.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz5a::calaRobota);
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.math.BigDecimal;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* Korzystamy z przygotowanej metody w MaszynaWczytujaca2 - wersja z listą */
public class CzytajILicz5b {
static void calaRobota() {
try {
File plik = new File(WyczarujPliki.DUZY_PLIK);
Map<String, BigDecimal> sumyDouble = MaszynaWczytujaca2.wczytajCalyPlik(plik)
.stream()
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumyDouble.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz5b::calaRobota);
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* Korzystamy z przygotowanej metody w MaszynaWczytujaca2 - wersja ze strumieniem sekwencyjnym */
public class CzytajILicz5c {
static void calaRobota() {
try {
Path plik = Paths.get(WyczarujPliki.DUZY_PLIK);
Map<String, BigDecimal> sumyDouble = MaszynaWczytujaca2.dajStrumien(plik, false)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumyDouble.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz5c::calaRobota);
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
/* Korzystamy z przygotowanej metody w MaszynaWczytujaca2 - wersja ze strumieniem równoległym */
public class CzytajILicz5d {
static void calaRobota() {
try {
Path plik = Paths.get(WyczarujPliki.DUZY_PLIK);
Map<String, BigDecimal> sumyDouble = MaszynaWczytujaca2.dajStrumien(plik, true)
.collect(Collectors.groupingBy(Transakcja::miasto,
Collectors.mapping(Transakcja::wartosc,
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
sumyDouble.forEach((k, v) -> System.out.printf(Locale.US, "%12s - %12.2f\n", k, v));
System.out.println();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Pomiary.zmierzCzasDzalania(CzytajILicz5d::calaRobota);
Pomiary.wypiszPamiec();
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.util.List;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
public class F1_SredniaWartoscTransakcji {
public static void main(String[] args) {
try {
List<Transakcja> lista = MaszynaWczytujaca2.wczytajCalyPlik(new File("rekordy.csv"));
System.out.println("Wczytano " + lista.size() + " rekordów");
double srednia = lista.stream()
.mapToDouble(Transakcja::wartoscDouble)
.average()
.getAsDouble();
System.out.println(srednia);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package sprzedaz.wydajnosc;
import java.util.Objects;
public class Opakowanie<T> {
private T value;
private Opakowanie(T v) {
this.value = v;
}
public static <T> Opakowanie<T> empty() {
return new Opakowanie<T>(null);
}
public static <T> Opakowanie<T> of(T value) {
return new Opakowanie<T>(value);
}
public T get() {
return value;
}
public void set(T value) {
this.value = value;
}
@Override
public String toString() {
return "{" + String.valueOf(value) + "}";
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Opakowanie other = (Opakowanie) obj;
return Objects.equals(value, other.value);
}
}
package sprzedaz.wydajnosc;
import java.util.function.Function;
public class Pomiary {
public static void zmierzCzasDzalania(Runnable runnable) {
long p = System.currentTimeMillis();
runnable.run();
long k = System.currentTimeMillis();
System.out.printf("t = %d\n", k - p);
}
public static void zmierzCzasDzalaniaRepeat(final Runnable runnable, final int repeat) {
long p = System.currentTimeMillis();
for(int i = 0; i < repeat; i++) {
runnable.run();
}
long k = System.currentTimeMillis();
System.out.printf("t = %d\n", k - p);
}
public static <T,R> void zmierzCzasDzalania(Function<T, R> funkcja, T arg) {
long p = System.currentTimeMillis();
Object res = funkcja.apply(arg);
long k = System.currentTimeMillis();
System.out.printf("t = %d\n", k - p);
}
public static void zmierzCzasDzalaniaIntString(Function<Integer, String> metoda, int n) {
long p = System.currentTimeMillis();
String str = metoda.apply(n);
long k = System.currentTimeMillis();
System.out.printf("n = %d, len = %d, t = %d\n", n, str.length(), k-p);
}
public static void wypiszPamiec() {
Runtime runtime = Runtime.getRuntime();
long used = (runtime.totalMemory() - runtime.freeMemory()) >> 20;
long total = runtime.totalMemory() >> 20;
System.out.printf("zajęta pamięć: %5d MB\n", used);
System.out.printf("cała pamięć: %5d MB\n", total);
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import sprzedaz.Transakcja;
// Ta seria programów porównuje wydajność różnych technik wczytywania danych z pliku.
// Zwracamy uwagę na czas oraz zajętą pamięć.
// UWAGA. Aby te przykłady zadziałały, wcześniej trzeba uruchomić "WyczarujPliki" i utworzyć pliki z większą ilością (powtórzonych) danych.
// Wersja ze Scanner, split i LinkedList - działa najwolniej
public class WczytajSprzedaz1 {
static List<Transakcja> wczytaj(File plik) throws IOException {
List<Transakcja> lista = new LinkedList<>();
try (Scanner sc = new Scanner(plik)) {
sc.nextLine();
while (sc.hasNextLine()) {
String linia = sc.nextLine();
String[] pola = linia.split(",");
LocalDate data = LocalDate.parse(pola[0]);
String miasto = pola[1];
String sklep = pola[2];
String kategoria = pola[3];
String towar = pola[4];
BigDecimal cena = new BigDecimal(pola[5]);
int sztuk = Integer.parseInt(pola[6]);
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.LinkedList;
import java.util.List;
import sprzedaz.Transakcja;
// Wersja używająca BufferedReader zamiast Scanner - działa szybciej
public class WczytajSprzedaz2 {
static List<Transakcja> wczytaj(File plik) throws IOException {
List<Transakcja> lista = new LinkedList<>();
// try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
try(BufferedReader reader = new BufferedReader(new FileReader(plik)) ) {
String linia = reader.readLine();
while ((linia = reader.readLine()) != null) {
String[] pola = linia.split(",");
LocalDate data = LocalDate.parse(pola[0]);
String miasto = pola[1];
String sklep = pola[2];
String kategoria = pola[3];
String towar = pola[4];
BigDecimal cena = new BigDecimal(pola[5]);
int sztuk = Integer.parseInt(pola[6]);
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import sprzedaz.Transakcja;
// Wersja używająca ArrayList zamiast LinkedList - działa szybciej
public class WczytajSprzedaz3 {
static List<Transakcja> wczytaj(File plik) throws IOException {
List<Transakcja> lista = new ArrayList<>();
try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
String linia = reader.readLine();
while ((linia = reader.readLine()) != null) {
String[] pola = linia.split(",");
LocalDate data = LocalDate.parse(pola[0]);
String miasto = pola[1];
String sklep = pola[2];
String kategoria = pola[3];
String towar = pola[4];
BigDecimal cena = new BigDecimal(pola[5]);
int sztuk = Integer.parseInt(pola[6]);
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import sprzedaz.Transakcja;
// Wersja wprowadzająca pomysł puli obiektów dla klas BigDecimal i LocalDate - zmniejszenie zajętości pamięci i drobna poprawa czasu wczytywania.
// W puli obiektów chodzi o to, aby nie tworzyć oddzielnych obiektów dla każdego wiersza danych,
// ale użyć referencji do obiektu, który został utworzony wcześniej, gdy w późniejszym wierszu pojawia się taka sama wartość
// daty lub ceny. Taka technika może dać duże oszczędności pamięci, jeśli w danych wejściowych jest dużo powtórzeń.
public class WczytajSprzedaz4 {
static List<Transakcja> wczytaj(File plik) throws IOException {
Map<String, LocalDate> pulaDat = new HashMap<>();
Map<String, BigDecimal> pulaCen = new HashMap<>();
List<Transakcja> lista = new ArrayList<>();
try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
String linia = reader.readLine();
while ((linia = reader.readLine()) != null) {
String[] pola = linia.split(",");
LocalDate data = pulaDat.get(pola[0]);
if(data == null) {
data = LocalDate.parse(pola[0]);
pulaDat.put(pola[0], data);
}
BigDecimal cena = pulaCen.get(pola[5]);
if(cena == null) {
cena = new BigDecimal(pola[5]);
pulaCen.put(pola[5], cena);
}
String miasto = pola[1];
String sklep = pola[2];
String kategoria = pola[3];
String towar = pola[4];
int sztuk = Integer.parseInt(pola[6]);
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import sprzedaz.Transakcja;
/* Naważniejsza rzecz - w tej wersji korzystamy ze String.intern()
Każdy wczytywany z pliku napis zamieniamy na napis o tej samej treści "z puli".
JVM utrzymuje pulę Stringów używanych przez aplikację.
Dla każdego napisu można odnaleźć odpowiadający mu napis z puli - wszystkie wystąpienia tego samego napisu
(np. "Warszawa") zostaną zastąpione odwołaniami do TEGO SAMEGO obiektu w pamięci.
Dzięki temu po wczytaniu dane zajmują mniej pamięci, GC ma mniej roboty, szybciej działa porównywanie napisów (a co za tym idzie np. HashMapa).
Używanie intern() w wersjach Javy do 8 włącznie działało nawet szybciej, niż poprzednie programy.
Od Java 11 czas wczytywania się pogarsza, ale wciąż bardzo zyskujemy na pamięci.
*/
public class WczytajSprzedaz5 {
static List<Transakcja> wczytaj(File plik) throws IOException {
Map<String, LocalDate> pulaDat = new HashMap<>();
Map<String, BigDecimal> pulaCen = new HashMap<>();
List<Transakcja> lista = new ArrayList<>();
try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
String linia = reader.readLine();
while ((linia = reader.readLine()) != null) {
String[] pola = linia.split(",");
int sztuk = Integer.parseInt(pola[6]);
LocalDate data = pulaDat.get(pola[0]);
if(data == null) {
data = LocalDate.parse(pola[0]);
pulaDat.put(pola[0], data);
}
BigDecimal cena = pulaCen.get(pola[5]);
if(cena == null) {
cena = new BigDecimal(pola[5]);
pulaCen.put(pola[5], cena);
}
String miasto = pola[1].intern();
String sklep = pola[2].intern();
String kategoria = pola[3].intern();
String towar = pola[4].intern();
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import sprzedaz.Transakcja;
// Zamiast zwykłej HashMap, używamy wersji ConcurrentHashMap,
// aby przygotować się do zrównoleglenia procesu wczytywania w ramach "MaszynaWczytujaca2".
// Używam też nowej operacji do "leniwej inicjalizacji" słowników - computeIfAbsent.
public class WczytajSprzedaz6 {
static List<Transakcja> wczytaj(File plik) throws IOException {
Map<String, LocalDate> pulaDat = new ConcurrentHashMap<>();
Map<String, BigDecimal> pulaCen = new ConcurrentHashMap<>();
List<Transakcja> lista = new ArrayList<>();
try(BufferedReader reader = Files.newBufferedReader(plik.toPath())) {
String linia = reader.readLine();
while ((linia = reader.readLine()) != null) {
String[] pola = linia.split(",");
int sztuk = Integer.parseInt(pola[6]);
LocalDate data = pulaDat.computeIfAbsent(pola[0], LocalDate::parse);
BigDecimal cena = pulaCen.computeIfAbsent(pola[5], BigDecimal::new);
String miasto = pola[1].intern();
String sklep = pola[2].intern();
String kategoria = pola[3].intern();
String towar = pola[4].intern();
Transakcja transakcja = new Transakcja(data, miasto, sklep, kategoria, towar, cena, sztuk);
lista.add(transakcja);
}
}
return lista;
}
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (IOException e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.util.List;
import sprzedaz.MaszynaWczytujaca2;
import sprzedaz.Transakcja;
// Wydzielenie wczytywania do oddzielnej klasy MaszynaWczytujaca2.
// W tamtej klasie zamiast HashMap używany jest ConcurrentHashMap.
public class WczytajSprzedaz7 {
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = MaszynaWczytujaca2.wczytajCalyPlik(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (Exception e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.util.List;
import sprzedaz.MaszynaWczytujaca1;
import sprzedaz.Transakcja;
// A tu dla porównania wywołanie gotowej metody wczytaj w "MaszynaWczytujaca1", czyli w stylu, jaki na zajęciach stosowaliśmy dla klasy Employee.
public class WczytajSprzedaz9 {
public static void main(String[] args) {
Pomiary.wypiszPamiec();
Opakowanie<List<Transakcja>> wynik = Opakowanie.empty();
System.out.println("\nczytam");
File plik = new File(WyczarujPliki.DUZY_PLIK);
Pomiary.zmierzCzasDzalania(() -> {
try {
List<Transakcja> lista = MaszynaWczytujaca1.wczytaj(plik);
wynik.set(lista); // aby GC nie usunął listy
System.out.println("Wczytano " + lista.size());
} catch (Exception e) {
e.printStackTrace();
}
});
Pomiary.wypiszPamiec();
System.out.println("\ngc");
System.gc();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Pomiary.wypiszPamiec();
System.out.println(wynik.get().size());
}
}
package sprzedaz.wydajnosc;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
public class WyczarujPliki {
public static final String DUZY_PLIK = "sprzedaz_200.csv";
public static void main(String[] args) {
try {
List<String> linie = Files.readAllLines(Paths.get("sprzedaz.csv"));
String naglowek = linie.getFirst();
linie.remove(0);
for(int n : new int[]{50, 200}) {
String plik = "sprzedaz_"+n+".csv";
System.out.println(plik);
zapiszPowielone(naglowek, linie, n, new File(plik));
}
System.out.println("Gotowe");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void zapiszPowielone(String naglowek, List<String> linie, int n, File file) throws FileNotFoundException {
try(PrintWriter out = new PrintWriter(file)) {
out.println(naglowek);
for(int tura = 0; tura < n; tura ++) {
for (String linia : linie) {
out.println(linia);
}
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment