-------------
Früher war mein Java-Hass auf ein paar Vorurteilen und einigen theoretischen Überlegungen begründet, aber nachdem ich nun an einem Java Projekt arbeite hat sich meine Abneigung konkretisiert. Betrachtet dazu folgende C++/Java-Programme.
Das Beispiel mag im ersten Moment künstlich aussehen, aber die Grundaufgabe ist eine Reale und besteht darin aus einer Serie von Objekten gewisse Statistiken auszurechnen.
Hier die C++-Version:
Code: Alles auswählen
#include <iostream>
#include <vector>
#include <string>
#include <map>
struct Datapoint {
const std::string wetter;
const unsigned niederschlag;
};
std::vector<Datapoint> tage{
{"Regen", 4}, {"Wolken", 33}, {"Schnee", 6}, {"Schnee", 4},
{"Sonne", 12}, {"Regen", 4}, {"Nebel", 0},
{"Wolken", 16},
{"Nebel", 19}, {"Schnee", 4}, {"Wolken", 14},
{"Schnee", 5}
};
int main()
{
std::map<std::string, std::pair<unsigned short, unsigned short>> counters;
for (auto datapoint : tage)
{
if (!counters.count(datapoint.wetter))
counters[datapoint.wetter] = std::make_pair(0u, 0u);
if (datapoint.niederschlag <= 12)
++counters[datapoint.wetter].first;
else
++counters[datapoint.wetter].second;
}
for (auto tagwetter : counters)
{
std::cout<<"An "<<tagwetter.first<<"tagen gab es "<<
tagwetter.second.first<<" mal wenig Niederschlag und "<<
tagwetter.second.second<<" mal viel Niederschlag.\n";
}
return 0;
}
Code: Alles auswählen
import java.util.*;
import java.util.Map.Entry;
import javafx.util.Pair;
class Maps {
static class Datapoint {
final String wetter; // final ist nicht const!!!
final int niederschlag; // kein unsigned? Schade :(
// default konstruktor explizit. Muss das sein? Ist
// das für den Compiler echt so schwierig?
public Datapoint(String wetter, int niederschlag)
{
this.wetter = wetter;
this.niederschlag = niederschlag;
}
}
static List<Datapoint> tage = new ArrayList<>(); // nicht im Konstruktor initialisierbar? Schade :(
static { // wo sind wir denn hier gelandet?
//Initializer Blocks sehen aus wie ne Krücke für fehlende Konstruktorinitialisierungen
tage.addAll(Arrays.asList( // addAll(asList(...)) ???
new Datapoint("Regen", 4), new Datapoint("Wolken", 33),
new Datapoint("Schnee", 6), new Datapoint("Schnee", 4),
new Datapoint("Sonne", 12), new Datapoint("Regen", 4), new Datapoint("Nebel", 0)
));
// oder doch lieber so?
tage.add(new Datapoint("Wolken", 16));
tage.add(new Datapoint("Nebel", 19));
tage.add(new Datapoint("Schnee", 4));
tage.add(new Datapoint("Wolken", 14));
tage.add(new Datapoint("Schnee", 5));
// new, new, new, new, new, .... Wisst ihr eigentlich was das für die
// Speicherfragmentierung bedeutet?
}
public static void main(String [] args)
{
Map<String, javafx.util.Pair<Integer, Integer>> counters = new HashMap<>();
// javafx.util.Pair? gibts nichtmal eine Pair klasse in der "Haupt"-Java-distribution?
// Um in eine "Collection" reinzugehen müssen die werte vom typ "Object"
// abgeleitet sein (C++-Äquivalent: void* ). Dazu kann man also nicht einmal "int" verwenden,
// sondern nur die Integer-Klasse.
for (Datapoint datapoint : tage)
{
javafx.util.Pair<Integer, Integer> pair = counters.get(datapoint.wetter);
if (pair == null)
{
pair = new javafx.util.Pair<Integer, Integer>(new Integer(0), new Integer(0));
// new, new, new. Hübsch, oder?
}
// wir können ein Integer-Objekt in einem Pair nicht inkrementieren.
// Deswegen vorher extra abspeichern!
Integer k = pair.getKey(), v = pair.getValue();
if (datapoint.niederschlag <= 12)
{
// wir können das Integer in dem Pair nicht einfach ersetzen.
// Deswegen ein neues Pair erstellen!
pair = new javafx.util.Pair<Integer, Integer>(k + 1, v);
}
else
{
pair = new javafx.util.Pair<Integer, Integer>(k, v + 1);
}
counters.put(datapoint.wetter, pair);
}
for (Entry<String, Pair<Integer, Integer>> tagwetter : counters.entrySet())
// Entry<String, Pair<Integer, Integer>>...blablala. Warum nicht einfach auto?
{
System.out.println("An " + tagwetter.getKey() + "tagen gab es " +
tagwetter.getValue().getKey() + " mal wenig Niederschlag und " +
tagwetter.getValue().getValue() + " mal viel Niederschlag.");
}
}
}