{"id":1067,"date":"2011-08-12T11:58:12","date_gmt":"2011-08-12T09:58:12","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/2011\/08\/aneinanderreihung-von-comparatoren\/"},"modified":"2011-08-12T11:58:12","modified_gmt":"2011-08-12T09:58:12","slug":"aneinanderreihung-von-comparatoren","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2011\/08\/aneinanderreihung-von-comparatoren\/","title":{"rendered":"Aneinanderreihung von Comparatoren"},"content":{"rendered":"<p>Oftmals ist das Ordnungskriterium aus mehreren Bedingungen zusammengesetzt, wie die Sortierung in einem Telefonbuch zeigt. Erst gibt es eine Sortierung nach dem Nachnamen, dann folgt der Vorname. Um diese mit einem Compartor-Objekt zu l\u00f6sen, m\u00fcssen entweder alle Einzelvergleiche in ein neues Compartor-Objekt verpackt werden, oder einzelne Comparatoren zu einem \u201eSuper\u201c-Comparator zusammengebunden werden \u2013 die zweite L\u00f6sung ist nat\u00fcrlich sch\u00f6ner, denn das erh\u00f6ht die Wiederverwendbarkeit, denn einzelne Comparatoren k\u00f6nnen dann leicht f\u00fcr andere Zusammenh\u00e4nge genutzt werden.<\/p>\n<p><strong>Comparatoren in eine Vergleichskette setzen<\/strong><\/p>\n<p>Am Anfang steht ein besonderer Comparator, der sich aus mehreren Comparatoren zusammensetzt. Immer dann, wenn ein Teil-Compartor bei zwei Objekten aussagt, dass sie gleich sind (der Vergleich liefert 0 ist), so soll der n\u00e4chste Comparator die Endscheidung f\u00e4llen \u2013 kann er das auch nicht, weil das Ergebnis wieder 0 ist, geht es zum n\u00e4chsten Vergleicher.<\/p>\n<p>Den Programmcode wollen wir einen neue Hilfsklasse ComparatorChain setzen:<\/p>\n<pre class=\"csharpcode\">package com.tutego.insel.util;\n\nimport java.util.*;\n\n<span class=\"rem\">\/**<\/span>\n<span class=\"rem\"> * A {@link Comparator} that puts one or more {@code Comparator}s in a sequence.<\/span>\n<span class=\"rem\"> * If a {@code Comparator} returns zero the next {@code Comparator} is taken.<\/span>\n<span class=\"rem\"> *\/<\/span>\n<span class=\"kwrd\">public<\/span> <span class=\"kwrd\">class<\/span> ComparatorChain&lt;E&gt; implements Comparator&lt;E&gt;\n{\n  <span class=\"kwrd\">private<\/span> List&lt;Comparator&lt;E&gt;&gt; comparatorChain = <span class=\"kwrd\">new<\/span> ArrayList&lt;Comparator&lt;E&gt;&gt;();\n  \n  <span class=\"rem\">\/**<\/span>\n<span class=\"rem\">   * Construct a new comparator chain from the given {@code Comparator}s.<\/span>\n<span class=\"rem\">   * The argument is not allowed to be {@code null}.<\/span>\n<span class=\"rem\">   * @param comparators Sequence of {@code Comparator}s<\/span>\n<span class=\"rem\">   *\/<\/span>\n  @SafeVarargs  <span class=\"rem\">\/\/ ab Java 7<\/span>\n  <span class=\"kwrd\">public<\/span> ComparatorChain( Comparator&lt;E&gt;... comparators )\n  {\n    <span class=\"kwrd\">if<\/span> ( comparators == <span class=\"kwrd\">null<\/span> )\n      <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> IllegalArgumentException( <span class=\"str\">&quot;Argument is not allowed to be null&quot;<\/span> );\n\n    Collections.addAll( comparatorChain, comparators );\n  }\n\n  <span class=\"rem\">\/**<\/span>\n<span class=\"rem\">   * Adds a {@link Comparator} to the end of the chain.<\/span>\n<span class=\"rem\">   * The argument is not allowed to be {@code null}.<\/span>\n<span class=\"rem\">   * @param comparator {@code Comparator} to add<\/span>\n<span class=\"rem\">   *\/<\/span>\n  <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">void<\/span> addComparator( Comparator&lt;E&gt; comparator )\n  {\n    <span class=\"kwrd\">if<\/span> ( comparator == <span class=\"kwrd\">null<\/span> )\n      <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> IllegalArgumentException( <span class=\"str\">&quot;Argument is not allowed to be null&quot;<\/span> );\n\n    comparatorChain.add( comparator );\n  }\n\n  <span class=\"rem\">\/**<\/span>\n<span class=\"rem\">   * {@inheritDoc}<\/span>\n<span class=\"rem\">   *\/<\/span>\n  @Override\n  <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">int<\/span> compare( E o1, E o2 )\n  {\n    <span class=\"kwrd\">if<\/span> ( comparatorChain.isEmpty() )\n      <span class=\"kwrd\">throw<\/span> <span class=\"kwrd\">new<\/span> UnsupportedOperationException(\n                  <span class=\"str\">&quot;Unable to compare without a Comparator in the chain&quot;<\/span> );\n\n    <span class=\"kwrd\">for<\/span> ( Comparator&lt;E&gt; comparator : comparatorChain )\n    {\n      <span class=\"kwrd\">int<\/span> order = comparator.compare( o1, o2 );\n      <span class=\"kwrd\">if<\/span> ( order != 0 )\n        <span class=\"kwrd\">return<\/span> order;\n    }\n\n    <span class=\"kwrd\">return<\/span> 0;\n  }\n}<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style><\/pre>\n<p>Die ComparatorChain k\u00f6nnen wir auf zwei Weisen mit den Comparator-Gliedern f\u00fcttern: einmal zu Initialisierungszeit im Konstruktor, und dann sp\u00e4ter noch \u00fcber die addComparator()-Methode. Beim Weg \u00fcber den Konstruktor ist ab Java 7 die Annotation @SafeVarargs zu nutzen, da sonst die Kombination eines Varargs und Generics auf der Nutzerseite zu einer Warnung f\u00fchrt.<\/p>\n<p>Ist kein Comparator intern in der Liste, wird das compare() eine Ausnahme ausl\u00f6sen. Der erste Comparator in der Liste ist auch das Vergleichsobjekt was zuerst gefragt wird. Liefert er ein Ergebnis ungleich 0 liefert das die R\u00fcckgabe der compare()-Methode. Ein Ergebnis gleich 0 f\u00fchrt zur Anfrage des n\u00e4chstes Comparators in der Liste.<\/p>\n<p>Wir wollen diese ComparatorChain f\u00fcr ein Beispiel nutzen, dass eine Liste nach Nach- und Vornamen sortiert.<\/p>\n<pre class=\"csharpcode\">package com.tutego.insel.util;\n\nimport java.util.*;\n\n<span class=\"kwrd\">public<\/span> <span class=\"kwrd\">class<\/span> ComparatorChainDemo\n{\n  <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">static<\/span> <span class=\"kwrd\">class<\/span> Person\n  {\n    <span class=\"kwrd\">public<\/span> String firstname, lastname;\n\n    <span class=\"kwrd\">public<\/span> Person( String firstname, String lastname )\n    {\n      <span class=\"kwrd\">this<\/span>.firstname = firstname;\n      <span class=\"kwrd\">this<\/span>.lastname  = lastname;\n    }\n\n    @Override <span class=\"kwrd\">public<\/span> String toString()\n    {\n      <span class=\"kwrd\">return<\/span> firstname + <span class=\"str\">&quot; &quot;<\/span> + lastname;\n    }\n  }\n\n  <span class=\"kwrd\">public<\/span> final <span class=\"kwrd\">static<\/span> Comparator&lt;Person&gt;\n    PERSON_FIRSTNAME_COMPARATOR = <span class=\"kwrd\">new<\/span> Comparator&lt;Person&gt;() {\n      @Override <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">int<\/span> compare( Person p1, Person p2 ) {\n        <span class=\"kwrd\">return<\/span> p1.firstname.compareTo( p2.firstname );\n      }\n    };\n\n  <span class=\"kwrd\">public<\/span> final <span class=\"kwrd\">static<\/span> Comparator&lt;Person&gt;\n    PERSON_LASTNAME_COMPARATOR = <span class=\"kwrd\">new<\/span> Comparator&lt;Person&gt;() {\n      @Override <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">int<\/span> compare( Person p1, Person p2 ) {\n        <span class=\"kwrd\">return<\/span> p1.lastname.compareTo( p2.lastname );\n      }\n    };\n\n  <span class=\"kwrd\">public<\/span> <span class=\"kwrd\">static<\/span> <span class=\"kwrd\">void<\/span> main( String[] args )\n  {\n    List&lt;Person&gt; persons = Arrays.asList(\n      <span class=\"kwrd\">new<\/span> Person( <span class=\"str\">&quot;Onkel&quot;<\/span>, <span class=\"str\">&quot;Ogar&quot;<\/span> ), <span class=\"kwrd\">new<\/span> Person( <span class=\"str\">&quot;Olga&quot;<\/span>, <span class=\"str\">&quot;Ogar&quot;<\/span> ),\n      <span class=\"kwrd\">new<\/span> Person( <span class=\"str\">&quot;Peter&quot;<\/span>, <span class=\"str\">&quot;Lustig&quot;<\/span> ), <span class=\"kwrd\">new<\/span> Person( <span class=\"str\">&quot;Lara&quot;<\/span>, <span class=\"str\">&quot;Lustig&quot;<\/span> ) );\n\n    Collections.sort( persons, PERSON_LASTNAME_COMPARATOR );\n    System.<span class=\"kwrd\">out<\/span>.println( persons );\n\n    Collections.sort( persons, PERSON_FIRSTNAME_COMPARATOR );\n    System.<span class=\"kwrd\">out<\/span>.println( persons );\n\n    Collections.sort( persons, <span class=\"kwrd\">new<\/span> ComparatorChain&lt;Person&gt;(\n        PERSON_LASTNAME_COMPARATOR, PERSON_FIRSTNAME_COMPARATOR ) );\n    System.<span class=\"kwrd\">out<\/span>.println( persons );\n  }\n}<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style><\/pre>\n<p>Die Ausgabe ist:<br \/>\n  <br \/>[Peter Lustig, Lara Lustig, Onkel Ogar, Olga Ogar]<\/p>\n<p>[Lara Lustig, Olga Ogar, Onkel Ogar, Peter Lustig]<\/p>\n<p>[Lara Lustig, Peter Lustig, Olga Ogar, Onkel Ogar]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oftmals ist das Ordnungskriterium aus mehreren Bedingungen zusammengesetzt, wie die Sortierung in einem Telefonbuch zeigt. Erst gibt es eine Sortierung nach dem Nachnamen, dann folgt der Vorname. Um diese mit einem Compartor-Objekt zu l\u00f6sen, m\u00fcssen entweder alle Einzelvergleiche in ein neues Compartor-Objekt verpackt werden, oder einzelne Comparatoren zu einem \u201eSuper\u201c-Comparator zusammengebunden werden \u2013 die zweite [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11],"tags":[],"class_list":["post-1067","post","type-post","status-publish","format-standard","hentry","category-insel"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1067","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=1067"}],"version-history":[{"count":0,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/1067\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=1067"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=1067"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=1067"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}