Java Backend: Ist diese Methode zu komplex?

Man könnte das auch so machen
Code:
List<List<List<Object>>> tables = new ArrayList<>(data.stream()
    .collect(Collectors.groupingBy(row -> row.get(0))).values());
tables.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0)))); // <- das ist denke ich noch falsch, müsste eher sowas wie a.get(0).get(0) sein

Würde mich echt interessieren, ob das gleiche Ergebnis rauskommt.
Ergänzung ()

Scheint ein Firefox-Problem zu sein, wenn ich von hier Code kopiere, passiert das auch:
https://pypi.org/project/fritzconnection/
 
Zuletzt bearbeitet:
tollertyp schrieb:
Würde mich echt interessieren, ob das gleiche Ergebnis rauskommt.
Das sollte eigentlich funktionieren ... Aber um das zu testen, müsste ich erst eine ganze Kette anstoßen, das will ich jetzt nicht machen.

Ich hab auch schon überlegt, einen Datenbank-Dump oder eine CSV zur Verfügung zu stellen, aber das sind teilw. sensible Daten (muss ja nicht jeder mein Konto kennen :D ). Und ein Beispiel bekomme ich jetzt nicht so schnell hin.

Jedenfalls wäre hier noch eine andere Version, die mir aber auch nicht zu 100 % zusagt ;) (zumal hier (zum Beispiel) das Runden auf zwei Nachkommastellen fehlt):

Java:
public class Report {
    record Entry(Date time, String asset, String type, double free, double locked, double sum,
            double usdFree, double usdLocked, double usdSum1, double usdSum2) {
        Entry(Date time) {
            this(time, "", "", 0d, 0d, 0d, 0d, 0d, 0d, 0d);
        }
        static Entry from(List<Object> row) {
            return new Entry(
                    (Date) row.get(0), (String) row.get(1), (String) row.get(2),
                    (double) row.get(3), (double) row.get(4), (double) row.get(5),
                    (double) row.get(6), (double) row.get(7), (double) row.get(8), (double) row.get(9));
        }
        Entry plus(Entry other) {
            return new Entry(time, "sum", "---",
                    free + other.free, locked + other.locked, sum + other.sum,
                    usdFree + other.usdFree, usdLocked + other.usdLocked,
                    usdSum1 + other.usdSum1, usdSum2 + other.usdSum2);
        }
    }
    record EntriesByTime(Date time, List<Entry> entries) {
        Entry getSums() {
            return entries.stream().reduce(new Entry(time), Entry::plus);
        }
    }
    List<EntriesByTime> getEntriesByTimes(List<List<Object>> data) {
        Map<Date, List<Entry>> entryMap = data.stream()
                .map(Entry::from).collect(Collectors.groupingBy(Entry::time));
        return entryMap.entrySet().stream()
                .map(mapEntry -> new EntriesByTime(mapEntry.getKey(), mapEntry.getValue()))
                .toList();               
    }
}
 
Ich sehe hier schon auch gute Ansätze, aber ich stimme dir zu, dass auch der Code nicht wirklich elegant wirkt - und wenn ich nicht schon viel vom anderen gelesen hätte, würde es mir auch schwerer fallen, ihn zu verstehen.

Grundsätzlich würde ich einen speziellen Typen für einzelne Einträge/Zeilen begrüßen. Wie der konkret modelliert wird, das hängt dann von den Anforderungen ab, also ob die Double-Werte nicht vielleicht in einem Array gespeichert werden statt in einzelnen Variablen usw...

Ob das Reduce wirklich die Lesbarkeit erhöht, das ist eine gute Frage. Reduce ist einfach etwas, was selten verwendet wird, hier mal so, wie es auch gedacht ist. Ob ich es in EntriesByTime als öffentiche Methode rein machen würde, das weiß ich nicht, kommt auf die Nutzung des Typs EntriesByTime an. Ich meine wenn es wirklich nur die Entries sind, dann ist es auch irgendwo okay, aber die Summe ist ja dann auch nur ein weiterer Entry, und wer sagt, dass dieser Entry dann nicht zu EntriesByTime gehört?
 
  • Gefällt mir
Reaktionen: CyborgBeta
Moin,

tollertyp schrieb:
Man könnte das auch so machen
List<List<List<Object>>> tables = new ArrayList<>(data.stream() .collect(Collectors.groupingBy(row -> row.get(0))).values()); tables.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0)))); // <- das ist denke ich noch falsch, müsste eher sowas wie a.get(0).get(0) sein
Würde mich echt interessieren, ob das gleiche Ergebnis rauskommt.

das funktioniert (mit einem zusätzlichen .get(0)). Ich kann jetzt auch ein paar "entschärfte" Beispieldaten zur Verfügung stellen:

Java:
  public static List<List<List<Object>>> getTodayData() throws Exception {
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    df.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));

    List<List<Object>> data = getTestData();

    List<List<List<Object>>> tables =
        new ArrayList<>(data.stream().collect(Collectors.groupingBy(row -> row.get(0))).values());
    tables.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0).get(0))));

    for (List<List<Object>> table : tables) {
      table.sort(
          Comparator.comparingDouble((List<Object> r) -> (double) r.get(8))
              .thenComparing(r -> (String) r.get(2)));
    }

    for (List<List<Object>> table : tables) {
      table.add(
          Stream.concat(
                  Stream.of(table.get(0).get(0), "sum", "---"),
                  IntStream.range(3, 10)
                      .mapToObj(i -> table.stream().mapToDouble(r -> (double) r.get(i)).sum()))
              .collect(Collectors.toCollection(ArrayList::new)));
    }

    for (List<List<Object>> table : tables) {
      for (List<Object> row : table) {
        row.set(0, df.format(new Date(((java.sql.Timestamp) row.get(0)).getTime())));
        IntStream.range(3, row.size())
            .forEach(i -> row.set(i, String.format("%.2f", (Double) row.get(i))));
      }
    }

    return tables;
  }

  public static List<List<Object>> getTestData() {
    String dumpData =
        """
        "63","2024-10-15 01:34:04","FDUSD","base","88.67368551","0.00000000","88.67368551","88.67368551","0.00000000","0.00000000","88.67368551",
        "64","2024-10-15 01:34:04","BTC","normal","0.00000000","0.00003000","0.00003000","0.00000000","1.97939640","1.97939640","1.97939640",
        "65","2024-10-15 01:34:04","PEPE","hide","0.03500000","0.00000000","0.03500000","0.00000038","0.00000000","0.00000000","0.00000038",
        "9993",
        "66","2024-10-15 01:34:04","BNB","hide","0.00964743","0.00000000","0.00964743","5.69970342","0.00000000","0.00000000","5.69970342",
        "9",
        "67","2024-10-15 01:34:04","EUR","ignore","0.10000000","0.00000000","0.10000000","0.00000000","0.00000000","0.00000000","0.00000000",
        "68","2024-10-15 01:34:04","NFT","ignore","836.07496490","0.00000000","836.07496490","0.00000000","0.00000000","0.00000000","0.00000000",
        "69","2024-10-15 01:34:04","ETHW","ignore","0.00524000","0.00000000","0.00524000","0.00000000","0.00000000","0.00000000","0.00000000",
        "70","2024-10-15 02:34:04","FDUSD","base","88.67368551","0.00000000","88.67368551","88.67368551","0.00000000","0.00000000","88.67368551",
        "71","2024-10-15 02:34:04","BTC","normal","0.00000000","0.00003000","0.00003000","0.00000000","1.97733750","1.97733750","1.97000000",
        "73374999999998",
        "72","2024-10-15 02:34:04","PEPE","hide","0.03500000","0.00000000","0.03500000","0.00000038","0.00000000","0.00000000","0.00000038",
        "73","2024-10-15 02:34:04","BNB","hide","0.00964743","0.00000000","0.00964743","5.70259765","0.00000000","0.00000000","5.70259765",
        "74","2024-10-15 02:34:04","EUR","ignore","0.10000000","0.00000000","0.10000000","0.00000000","0.00000000","0.00000000","0.00000000",
        "75","2024-10-15 02:34:04","NFT","ignore","836.07496490","0.00000000","836.07496490","0.00000000","0.00000000","0.00000000","0.00000000",
        "76","2024-10-15 02:34:04","ETHW","ignore","0.00524000","0.00000000","0.00524000","0.00000000","0.00000000","0.00000000","0.00000000",
        "77","2024-10-15 03:34:04","FDUSD","base","84.68387551","0.00000000","84.68387551","84.68387551","0.00000000","0.00000000","84.68387551",
        "78","2024-10-15 03:34:04","BTC","normal","0.00000000","0.00003000","0.00003000","0.00000000","1.96849530","1.96849530","1.96000000",
        "84952999999997",
        "79","2024-10-15 03:34:04","DOGE","normal","0.00000000","17.00000000","17.00000000","0.00000000","1.98849000","1.98849000","1.98849000",
        "000000002",
        "80","2024-10-15 03:34:04","LTC","normal","0.00000000","0.02980000","0.02980000","0.00000000","1.99809000","1.99809000","1.99809000",
        "81","2024-10-15 03:34:04","PEPE","hide","0.03500000","0.00000000","0.03500000","0.00000038","0.00000000","0.00000000","0.00000038",
        "82","2024-10-15 03:34:04","BNB","hide","0.00964234","0.00000000","0.00964234","5.66391228","0.00000000","0.00000000","5.66391228",
        "83","2024-10-15 03:34:04","EUR","ignore","0.10000000","0.00000000","0.10000000","0.00000000","0.00000000","0.00000000","0.00000000",
        "84","2024-10-15 03:34:04","NFT","ignore","836.07496490","0.00000000","836.07496490","0.00000000","0.00000000","0.00000000","0.00000000",
        "85","2024-10-15 03:34:04","ETHW","ignore","0.00524000","0.00000000","0.00524000","0.00000000","0.00000000","0.00000000","0.00000000",
        "86","2024-10-15 04:34:04","FDUSD","base","82.71880135","0.00000000","82.71880135","82.71880135","0.00000000","0.00000000","82.71880135",
        "87","2024-10-15 04:34:04","DOGE","normal","0.00000000","17.00000000","17.00000000","0.00000000","1.99002000","1.99002000","1.99002000",
        "88","2024-10-15 04:34:04","LTC","normal","0.00000000","0.02980000","0.02980000","0.00000000","2.00345400","2.00345400","2.00345400",
        "89","2024-10-15 04:34:04","BTC","normal","0.00003000","0.00003000","0.00006000","1.97082030","1.97082030","3.94164060","3.94164060",
        "90","2024-10-15 04:34:04","PEPE","hide","0.03500000","0.00000000","0.03500000","0.00000038","0.00000000","0.00000000","0.00000038",
        "91","2024-10-15 04:34:04","BNB","hide","0.00963983","0.00000000","0.00963983","5.66050935","0.00000000","0.00000000","5.66050935",
        "92","2024-10-15 04:34:04","EUR","ignore","0.10000000","0.00000000","0.10000000","0.00000000","0.00000000","0.00000000","0.00000000",
        "93","2024-10-15 04:34:04","NFT","ignore","836.07496490","0.00000000","836.07496490","0.00000000","0.00000000","0.00000000","0.00000000",
        "94","2024-10-15 04:34:04","ETHW","ignore","0.00524000","0.00000000","0.00524000","0.00000000","0.00000000","0.00000000","0.00000000",
        """;
    List<List<Object>> list = new ArrayList<>();
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    dumpData
        .lines()
        .forEach(
            l -> {
              String[] split = l.split(",");
              if (split.length == 11) {
                List<Object> list2 = new ArrayList<>();
                try {
                  String s = split[1];
                  String v = s.startsWith("\"") ? s.substring(1, s.length() - 1) : s;
                  list2.add(new java.sql.Timestamp(df.parse(v).getTime()));
                } catch (ParseException e) {
                  throw new RuntimeException(e);
                }
                for (int i = 2; i < split.length; i++) {
                  String s = split[i];
                  String v = s.startsWith("\"") ? s.substring(1, s.length() - 1) : s;
                  try {
                    double d = Double.parseDouble(v);
                    list2.add(d);
                  } catch (NumberFormatException ignore) {
                    list2.add(v);
                  }
                }
                list.add(list2);
              }
            });
    return list;
  }

  public static void main(String[] args) throws Exception {
    List<List<List<Object>>> data = getTodayData();
    for (List<List<Object>> table : data) {
      for (List<Object> row : table) {
        System.out.println(row);
      }
      System.out.println();
    }
  }

Nicht wundern, Zeile 11 bis 15 habe ich noch hinzugefügt, und stellt noch mal eine zusätzliche Sortierung nach der 1. Summe und Typ dar. Leider muss man dem Lambda-Konstrukt am Anfang da den Typ angeben ... oder aber man verwendet zwei sort-Aufrufe, also kein Chaining. ;) Das ist noch etwas "ruckelig" ...
Ergänzung ()

Mir ist gerade noch etwas aufgefallen.

Eigentlich sollte nach Type, Sum 1 und nach Asset-Name (wenn Type und Sum 1 gleich sind) sortiert werden. Eigentlich wird das auch durch die Datenbank sichergestellt, weil die Daten schon in der richtigen Reihenfolge in der Datenbank stehen. Aber das neue groupingBy verwendet intern eine Map, die diese Reihenfolge wieder zerstört.

Es wären also anschließend noch drei Sort-Aufrufe, jeweils tabellenweise, notwendig.
 
Zuletzt bearbeitet:
CyborgBeta schrieb:
Eigentlich sollte nach Type, Sum 1 und nach Asset-Name (wenn Type und Sum 1 gleich sind) sortiert werden. Eigentlich wird das auch durch die Datenbank sichergestellt, weil die Daten schon in der richtigen Reihenfolge in der Datenbank stehen. Aber das neue groupingBy verwendet intern eine Map, die diese Reihenfolge wieder zerstört.

Es wären also anschließend noch drei Sort-Aufrufe, jeweils tabellenweise, notwendig.
Also eventuell könnten auch andere Aufrufe wie das hier die Reihenfolge erhalten:
Code:
Collectors.groupingBy(
                row -> row.get(0),
                LinkedHashMap::new,   // Verwende LinkedHashMap statt HashMap, um Sortierung aufrecht zu erhalten
                Collectors.toList()
            )

Die Sortierung dann wieder vorher machen.

Und grundsätzlich halte ich es für keine gute Strategie, dass die Reihenfolge, in der die Datenbank die Daten liefert, implizit richtig ist - wobei ich jetzt auch nicht weiß, was MDB.get() genau macht - vielleicht steckt da ja eine Sortierung explizit drin.
 
  • Gefällt mir
Reaktionen: CyborgBeta
Danke. :D

tollertyp schrieb:
wobei ich jetzt auch nicht weiß, was MDB.get() genau macht

Das ist eine "blöde" Methode, die macht eigentlich nichts Besonderes:

Java:
  public static List<List<Object>> get() throws Exception {
    try (Connection c = open()) {
      try (Statement s = c.createStatement()) {
        ResultSet resultSet = s.executeQuery("SELECT * FROM bina;");
        List<List<Object>> res = new ArrayList<>();
        while (resultSet.next()) {
          List<Object> r = new ArrayList<>();
          r.add(resultSet.getTimestamp("at"));
          r.add(resultSet.getString("asset"));
          r.add(resultSet.getString("type"));
          r.add(resultSet.getDouble("free"));
          r.add(resultSet.getDouble("locked"));
          r.add(resultSet.getDouble("sum"));
          r.add(resultSet.getDouble("free_usd"));
          r.add(resultSet.getDouble("locked_usd"));
          r.add(resultSet.getDouble("sum1_usd"));
          r.add(resultSet.getDouble("sum2_usd"));
          res.add(r);
        }
        return res;
      }
    }
  }

Ich hatte da (bewusst) keine "tiefergehende Logik" bzw. keine komplizierte Anfrage umgesetzt.

... Und das "add" sieht so aus:

Java:
  public static void add(List<List<Object>> list) throws Exception {
    final java.sql.Timestamp ts = new java.sql.Timestamp(System.currentTimeMillis());
    try (Connection c = open()) {
      for (List<Object> os : list) {
        try (PreparedStatement ps =
            c.prepareStatement(
                "INSERT INTO bina (at, asset, type, free, locked, sum, free_usd, locked_usd, sum1_usd, sum2_usd) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")) {
          ps.setTimestamp(1, ts);
          ps.setString(2, (String) os.get(0));
          ps.setString(3, (String) os.get(1));
          ps.setDouble(4, (double) os.get(2));
          ps.setDouble(5, (double) os.get(3));
          ps.setDouble(6, (double) os.get(4));
          ps.setDouble(7, (double) os.get(5));
          ps.setDouble(8, (double) os.get(6));
          ps.setDouble(9, (double) os.get(7));
          ps.setDouble(10, (double) os.get(8));
          ps.executeUpdate();
        }
      }
    }
  }
 
Okay, also die sortiert nicht, was ich befrüchtet habe.
Grundsätzlich halte ich es wie gesagt für keine gute Idee sich darauf zu verlassen, dass die Datenbank die Daten in der gewünschten Reihenfolge liefert. Kann sein, dass man sich bei der aktuell gewählten Datenbank/Implementierung drauf verlassen kann, ob das aber in Zukunft weiterhin so ist, wer garantiert das?
 
  • Gefällt mir
Reaktionen: CyborgBeta
Um sich inspirieren zu lassen kann man auch toll LLM Technologie abfragen. Man muss halt damit zusammen arbeiten und nicht gleich DIE Lösung erwarten. Aber aufpassen mit sensiblen Daten. Am besten LLM Zugriff vom Arbeitgeber zur Verfügung gestellt nutzen. Da der Code hier eh schon im Forum öffentlich ist, habe ich es aber mal im Sinne der Diskussion durchgeführt...

Siehe Beispiel unten: ob es valide ist weiß ich nicht, aber Ideengeber ist es alle mal.

Prompt:
"Du bist java Experte im Refactoring.
Der folgende Code ist nicht sehr verständlich und soll ein wenig in Methoden aufgeteilt werden. Sprechende Namen sind wichtig.

Hier der Code: <Code aus Post 1>"

Antwort LLM :
public static List<List<List<Object>>> getTodayData() throws Exception {
DateFormat df = createDateFormatForBerlinTimezone();
List<List<Object>> data = MDB.get();

sortDataByTimestamp(data);

List<List<List<Object>>> groupedTables = groupDataByTimestamp(data);
addSumRowToTables(groupedTables);
formatTableData(groupedTables, df);

return groupedTables;
}

private static DateFormat createDateFormatForBerlinTimezone() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
return df;
}

private static void sortDataByTimestamp(List<List<Object>> data) {
data.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0))));
}

private static List<List<List<Object>>> groupDataByTimestamp(List<List<Object>> data) {
List<List<List<Object>>> tables = new ArrayList<>();
for (int i = 0; i < data.size(); ) {
List<List<Object>> table = new ArrayList<>();
boolean isFirstEntry = true;
while (isFirstEntry || i < data.size() && data.get(i - 1).get(0).equals(data.get(i).get(0))) {
table.add(data.get(i++));
isFirstEntry = false;
}
tables.add(table);
}
return tables;
}

private static void addSumRowToTables(List<List<List<Object>>> tables) {
for (List<List<Object>> table : tables) {
List<Object> sumRow = createSumRowForTable(table);
table.add(sumRow);
}
}

private static List<Object> createSumRowForTable(List<List<Object>> table) {
return Stream.concat(
Stream.of(table.get(0).get(0), "sum", "---"),
IntStream.range(3, 10)
.mapToObj(i -> table.stream().mapToDouble(r -> (double) r.get(i)).sum())
).collect(Collectors.toCollection(ArrayList::new));
}

private static void formatTableData(List<List<List<Object>>> tables, DateFormat df) {
for (List<List<Object>> table : tables) {
for (List<Object> row : table) {
formatRowData(row, df);
}
}
}

private static void formatRowData(List<Object> row, DateFormat df) {
row.set(0, df.format(new Date(((java.sql.Timestamp) row.get(0)).getTime())));
IntStream.range(3, row.size())
.forEach(i -> row.set(i, String.format("%.2f", (Double) row.get(i))));
}
 
tollertyp schrieb:
wer garantiert das?
Es gibt eine id-Spalte:

Java:
  private static void createBina(Connection c) throws Exception {
    try (Statement s = c.createStatement()) {
      s.execute(
          "CREATE TABLE IF NOT EXISTS bina (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, at DATETIME, asset TEXT, type TEXT, free DOUBLE, locked DOUBLE, sum DOUBLE, free_usd DOUBLE, locked_usd DOUBLE, sum1_usd DOUBLE, sum2_usd DOUBLE);");
    }
  }

Aber, zugegebenermaßen ist das auch keine Garantie ...
 
@christkies:
Wenn es dann auch noch formatiert wäre, wäre es fast schon leserlich.

@CyborgBeta: Ja, keine Garantie. Was man nicht selten macht, gerade wenn es um Assoziationen geht, ist eine zusätzliche Order-Spalte. Die Order gilt dann immer nur innerhalb der "Gruppe", also für alle mit gleichem Timestamp. Der muss also nicht unique sein, die Kombination aus Timestamp und Order schon. Den würdest du einfach in der Schleife in add hochzählen.

Grundsätzlich ist die ID aber schon auf fortlaufend und aufsteigend - so lange eben die Sequenz nicht überläuft oder anderweitig zurückgesetzt wird.
 
  • Gefällt mir
Reaktionen: CyborgBeta
@christkies : Ohne jemanden zu nahe treten zu wollen, aber ich glaube, ChatGPT verschlimmbessert es in diesem Fall.
Ergänzung ()

tollertyp schrieb:
Grundsätzlich ist die ID aber schon auf fortlaufend und aufsteigend - so lange eben die Sequenz nicht überläuft oder anderweitig zurückgesetzt wird.
Anwendungsfall: Es kommen pro Stunde etwa 10 Zeilen hinzu, also so schnell läuft da nix über. ;)
 
Erst mal vernünftig formatiert:
Code:
public static List<List<List<Object>>> getTodayData() throws Exception {
   DateFormat df = createDateFormatForBerlinTimezone();
   List<List<Object>> data = MDB.get();
   
   sortDataByTimestamp(data);
   
   List<List<List<Object>>> groupedTables = groupDataByTimestamp(data);
   addSumRowToTables(groupedTables);
   formatTableData(groupedTables, df);

   return groupedTables;
}

private static DateFormat createDateFormatForBerlinTimezone() {
   DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   df.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
   return df;
}

private static void sortDataByTimestamp(List<List<Object>> data) {
   data.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0))));
}

private static List<List<List<Object>>> groupDataByTimestamp(List<List<Object>> data) {
   List<List<List<Object>>> tables = new ArrayList<>();
   for (int i = 0; i < data.size(); ) {
       List<List<Object>> table = new ArrayList<>();
       boolean isFirstEntry = true;
       while (isFirstEntry || i < data.size() && data.get(i - 1).get(0).equals(data.get(i).get(0))) {
           table.add(data.get(i++));
           isFirstEntry = false;
       }
       tables.add(table);
   }
   return tables;
}

private static void addSumRowToTables(List<List<List<Object>>> tables) {
   for (List<List<Object>> table : tables) {
       List<Object> sumRow = createSumRowForTable(table);
       table.add(sumRow);
   }
}

private static List<Object> createSumRowForTable(List<List<Object>> table) {
   return Stream.concat(
           Stream.of(table.get(0).get(0), "sum", "---"),
           IntStream.range(3, 10)
                   .mapToObj(i -> table.stream().mapToDouble(r -> (double) r.get(i)).sum())
   ).collect(Collectors.toCollection(ArrayList::new));
}

private static void formatTableData(List<List<List<Object>>> tables, DateFormat df) {
   for (List<List<Object>> table : tables) {
       for (List<Object> row : table) {
           formatRowData(row, df);
       }
   }
}

private static void formatRowData(List<Object> row, DateFormat df) {
   row.set(0, df.format(new Date(((java.sql.Timestamp) row.get(0)).getTime())));
   IntStream.range(3, row.size())
           .forEach(i -> row.set(i, String.format("%.2f", (Double) row.get(i))));
}


Finde auch nicht alles gut, was die KI da gemacht hat. Nehmen wir das Beispiel:
Code:
private static void sortDataByTimestamp(List<List<Object>> data) {
   data.sort(Comparator.comparing(a -> ((java.sql.Timestamp) a.get(0))));
}
Ich finde die Methode schrecklich. Was ich eher gemacht hätte, wäre eine Metrhode, die den Comparator liefert. "data.sort" ist schon aussagekräftig genug.

Also dass es irgendwie so aussieht:
Code:
data.sort(getTableSortComparator());
 
  • Gefällt mir
Reaktionen: CyborgBeta
tollertyp schrieb:
die Kombination aus Timestamp und Order schon. Den würdest du einfach in der Schleife in add hochzählen.
Das klingt ein wenig nach einer zusammengesetzten Schlüssel-Spalte.

Datenbanken ist schon etwas länger her bei mir, aber ich denke, das sollte eher vermieden werden.
 
CyborgBeta schrieb:
Anwendungsfall: Es kommen pro Stunde etwa 10 Zeilen hinzu, also so schnell läuft da nix über. ;)
Das denke ich auch. Insofern würde ich schon sagen, dass die ID mit autoinkrement sicher genug für eine Sortierung ist.

Und nein, kein zusammengesetzter Schlüssel, einfach ein Constraint über zwei Spalten. Und mit "Den" meinte ich wohl "Den Wert von Order"
 
  • Gefällt mir
Reaktionen: CyborgBeta
Danke erst mal, dann werd' ich später mal "refactoren" und Seite 3 und 4 dieses Themas beachten. 😬
 
Bedenkt, Prompting ist "Key".

In meinem userprompt bin ich ja eher auf die Strukturierung eingegangen und für die Benennung der Methoden und wie man es aufsplitten könnte, hat das LLM eine brauchbare Idee geliefert.

Im nächsten Schritt könnte man den Code in den Methoden ja auch noch mit Hilfe der KI weiter refactoren. Oder halt selbstständig.

Am Ende ist es nur ein Werkzeug und kein Lösungslieferer.
Ob es ein gutes Werkzeug ist bestimmt zu einem sehr großen Teil der Userprompt oder unter Umständen auch die ganze Chathistorie der laufenden Session.

Oft ist es auch besser neue Chats zu starten, weil die vorangegangene Historie das LLM von der eigentlich aktuellen Anfrage ablenkt.
 
  • Gefällt mir
Reaktionen: CyborgBeta
CyborgBeta schrieb:
Jedenfalls wäre hier noch eine andere Version, die mir aber auch nicht zu 100 % zusagt ;) (zumal hier (zum Beispiel) das Runden auf zwei Nachkommastellen fehlt):

Die typisierte Variante gefällt mir viel besser. Wäre gut, wenn die Typen direkt von den Datenbankmethoden mitkämen (ggf mit einem ausgeschriebenen Namen der Datenbanktabelle), da du ja dort sowieso jedes Feld einzeln behandelst (List<Object> ist Murks):
public static List<Bina> get() throws Exception {
public static void add(List<Bina> list) throws Exception {

Dann machst du halt noch einen Typ "BinaFormatted" o.ä., der halt dann nur Strings enthält für die formatierte Ausgabe.
 
Mir auch.

Ich würde das ganze aber vermutlich schon komplett anders modellieren auf Datenbank-Ebene. Und die Summe auch direkt berechnen beim Einfügen, und nicht beim Lesen.
 
Hmpf ... Man könnte auch einen ORM verwenden (JPA oder eine GitHub-Lib), aber ehrlich, das ist für diesen Anwendungsfall eigentlich zu aufwendig. Siehe auch https://stackoverflow.com/a/1483378 (lehnt ORMs generell ab)

Der hier sähe vielversprechend aus: https://modelmapper.org/

Ich bin noch nicht ganz d'accord damit, für wirklich alles eine Record-Klasse einzufügen.
Ergänzung ()

https://ormlite.com/ das sieht auch gut aus. Damit hatte ich schon mal etwas gemacht auch.
 
Zuletzt bearbeitet:
Könnte man. Aber für die Modellierung (also den Entwurf der Datenmodells) sollte es eigentlich egal sein, ob ORM oder nicht.
 
  • Gefällt mir
Reaktionen: CyborgBeta
Zurück
Oben