Dynamischer Komparator für Objekte mit ComparatorChain / Sudo Null IT News

Guten Tag, schreibt ein potenzieller Java-Entwickler. Ich bin kürzlich auf die folgende allgemeine Aufgabe gestoßen: Schreiben Sie einen mehrstufigen Komparator, um eine Sammlung einfacher Objekte zu sortieren.

Nach dem Studium dieses Problems entstand der Wunsch, einen Komparator für eine Klasse zu schreiben, der sich dynamisch ändern kann, wenn Klassenfelder und (oder) von außen eingestellte Sortierparameter geändert werden.

Also das Wichtigste zuerst. Es gibt einige Produktklassen:

import java.util.Formatter; Import lombok.Getter; Import lombok.Setter; @Setter @Getter öffentliche Klasse Produkt { privater Zeichenfolgenname; privat Ganzzahliger Satz; privater doppelter Preis; public Product(String name, Integer rate, Double price) { this.name = name; this.rate = Rate; this.price = Preis; } @Override public String toString() {String shortName = name.substring(0, Math.min(name.length(), 18)); return new Formatter().format(“name: %-20s rate: %8d price: %8.2f”, shortName, rate, price) .toString(); } }

Wenn die Richtung (ASC, DESC) und die Sortierreihenfolge im Voraus bekannt sind, dann kann dieses Problem leicht durch die folgende Methode gelöst werden:

public static List sortMethod(List products){ return products.stream() .sorted(Comparator.comparing(Product::getName) .thenComparing(Comparator.comparing(Product::getRate).reversed()) .thenComparing(Product::getPrice)) .toList(); }

Ähnliche Aktionen können mit CompareToBuilder.class oder anderen mir noch nicht bekannten Bibliotheken durchgeführt werden.

Was aber, wenn die Zusammensetzung der Klassenfelder nicht im Voraus bekannt ist und die Sortierparameter in einer separaten Datei gespeichert sind und auch beliebig eingestellt werden können? So schreiben Sie einen dynamischen Komparator, der ohne Änderung des Codes funktioniert, wenn die Felder der Entität selbst und die Sortierparameter geändert werden.

Wir haben die oben gezeigte Produktklasse und die Komparatorparameter, die in der View-XML-Datei enthalten sind:

asc asc desc

Das erste, was zu tun ist, ist diese Datei zu parsen und die Parameter unseres zukünftigen Komparators in eine bestimmte Struktur zu schreiben, die es uns ermöglicht, die Reihenfolge der darin geschriebenen Daten zu speichern. Ich habe dafür LinkedHashMap verwendet, wobei SortType ein Enum der Form ist:

Paket org.example.sort; Import lombok.Getter; öffentliche Aufzählung SortType {ASC(1), DESC(-1); @Getter privater int-Wert; SortType(int i) { dieser Wert = i; } }

Meine XMLParser.class sieht so aus, vielleicht nicht die beste und optimale, aber darum geht es in diesem Artikel nicht. Ich mache Sie darauf aufmerksam, dass unsere Product.class und ein Pfad zu einer Datei mit Sortierparametern als Parameter der Methode getSortTypeMap() verwendet werden, was es uns ermöglicht, über die dynamische Konstruktion der Argumente der Methode getComparatorBySortMap() zu sprechen der zukünftigen ComparatorFactory.class.

java.io.IOException importieren; import java.lang.reflect.Field; java.util.LinkedHashMap importieren; java.util.List importieren; javax.xml.parsers.DocumentBuilder importieren; import javax.xml.parsers.DocumentBuilderFactory; javax.xml.parsers.ParserConfigurationException importieren; javax.xml.xpath.XPath importieren; javax.xml.xpath.XPathConstants importieren; javax.xml.xpath.XPathExpression importieren; javax.xml.xpath.XPathFactory importieren; import lombok.SneakyThrows; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class XMLParser { @SneakyThrows public static LinkedHashMap getSortTypeMap (Class clazz, String path) { LinkedHashMap sortTypeMap = new LinkedHashMap<>(); List-Felder = List.of(clazz.getDeclaredFields()); DocumentBuilder documentBuilder; Dokument Dokument = null; try { documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); document = documentBuilder.parse (Pfad); } catch (SAXException | ParserConfigurationException | IOException e) {e.printStackTrace(); } XPathFactory pathFactory = XPathFactory.newInstance(); XPath xpath = pathFactory.newXPath(); XPathExpression expr = xpath.compile(“//sort/child::*”); NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++) { Knoten n = nodes.item(i); Feld field = fields.stream().filter(t -> t.getName().equals(n.getNodeName())) .findFirst() .orElse(null); if (field != null) { if (n.getTextContent().toUpperCase().equals(SortType.ASC.toString())) { sortTypeMap.put(field, SortType.ASC); } if (n.getTextContent().toUpperCase().equals(SortType.DESC.toString())) { sortTypeMap.put(field, SortType.DESC); } } } sortTypeMap zurückgeben; } }

Und nun die Klasse selbst, mit der Sie den notwendigen Komparator generieren können und die auf der Verwendung von ComparatorChain.class und BeanComparator.class basiert:

import java.lang.reflect.Field; java.util.LinkedHashMap importieren; java.util.Map importieren; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections4.comparators.ComparatorChain; public class ComparatorFactory { public ComparatorChain getProductComparatorBySortMap( LinkedHashMap sortTypeMap) { if (sortTypeMap.isEmpty()) { return null; } ComparatorChain Kette = new ComparatorChain<>(); Zeichenfolge parameterName; boolesche Richtung; for (Map.Entry sortParametr: sortTypeMap.entrySet()) { parameterName = sortParametr.getKey().getName(); Richtung = sortParameter.getValue().getValue() <= 0; chain.addComparator (neuer BeanComparator<>(parameterName), Richtung); } Rückgabekette; } }

Als Ergebnis erhalten wir die Möglichkeit, Komparatoren basierend auf den Daten über die Klasse und die Sortierreihenfolge zu generieren, wobei sich sowohl die Klasse als auch die Reihenfolge ändern können.

Ich entschuldige mich im Voraus für mögliche Fehler im Code und das Fehlen einer tieferen Analyse der Geschwindigkeit dieser Methode, mögliche Fehler und Mängel, die ich aufgrund mangelnder Erfahrung in der kommerziellen Programmierung nicht in dem Artikel widerspiegeln konnte.

Über Kommentare unter meinem ersten Artikel freue ich mich. Und ich hoffe, dass jemand, der einen “jungen” Java-Entwickler wie mich braucht, es liest.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *