2016-10-20 4 views
1

Ich habe eine Karte von Autos Map<String, List<Car>>, die von getCarsMap() Methode zurückgegeben werden kann, wo Schlüssel Modell des Autos ist, und Wert ist eine Liste der Autos des gleichen Modells.Java Stream-Code-Verbesserung

Ich möchte Car addCar(Car car) Funktion verbessern. Denn jetzt habe ich dieses ein bisschen hässlich Frieden Code

public Car addCar(Car car) { 
    if(getCarsMap().entrySet().stream().anyMatch(es -> es.getKey().equals(car.getModel()))){ 
     if(!getCarsMap().get(car.getModel()).contains(car)){ 
      getCarsMap().get(car.getModel()).add(car); 
     } 
    }else{ 
     List<Car> tmpList = new ArrayList<Car>(); 
     tmpList.add(car); 
     getCarsMap().put(car.getModel(), tmpList) ; 
    } 
    return car; 
} 

Außerdem müssen etwas ähnliches für removeCar(Car car) schreiben, aber hoffe, es wird mit einigen netten addCar Methode als Vorlage einfacher sein.

+1

Post, die auch hier in Frage http://codereview.stackexchange.com/ –

+2

@ ΦXocę 웃 Пepeúpa ツ No. Nicht Crossposting vorschlagen. Btw: http://meta.codereview.stackexchange.com/questions/5777/a-guide-to-code-review-for-stack-overflow-users – Tom

+3

'if (getCarsMap(). EntrySet(). Stream() .anyMatch (es -> es.getKey(). equals (car.getModel()))) Dies ist nur ein schlechterer Weg, 'getCarsMap() zu schreiben. containsKey (car.getModel())'. Warum verwenden Sie eine "Liste", wenn Sie keine Duplikate wollen? Und warum benutzt du 'getBoatsMap()' im 'else' Block? – Tom

Antwort

1

Meine Idee - verlassen Sie sich auf berechnen method von Map.

So meiner Methode populateMapWith Prozess aktuelle Karte nach Ihrem Fall:

  • wenn Werteliste ist leer - neue erstellen, Element, fügt

  • falls vorhanden, kartieren Elemente nur hinzufügen zur aktuellen Liste

sowie removeFromMap nach dem Entfernen.

I illustriert es mit Objektklasse, nur um den Fall zu vereinfachen

public class BaseTest { 

    private Map<String, List<Object>> myMap = new HashMap<>(); 

    @Test 
    public void testName() throws Exception { 
     Object car1 = new Object() { 
      @Override 
      public String toString() { 
       return "car1"; 
      } 
     }; 

     Object car2 = new Object() { 
      @Override 
      public String toString() { 
       return "car1"; 
      } 
     }; 

     populateMap(car1); 
     populateMap(car2); 

     assertEquals(2, myMap.get("car1").size()); 

     removeFromMap(car2); 

     assertEquals(1, myMap.get("car1").size()); 
    } 

    private void populateMap(Object o) { 
     myMap.computeIfAbsent(o.toString(), key -> new ArrayList<>()).add(o); 
    } 

    private void removeFromMap(Object o) { 
     myMap.computeIfPresent(o.toString(), (key,list) -> { list.remove(o); return list;}); 
    } 
} 

UPD: verbesserte Methoden nach einer Diskussion mit Holger

+3

Beachten Sie die Existenz, wenn die spezialisierten 'compute ...' Methoden, zum Hinzufügen: 'myMap.computeIfAbsent (o.toString(), Schlüssel -> new ArrayList <>()) .add (o); 'und zum Entfernen:' myMap.computeIfPresent (o.toString(), (Schlüssel, Liste) -> {list.remove (o); return list;}); 'oder wenn du putzen willst up leere Listen: 'myMap.computeIfPresent (o.toString(), (Schlüssel, Liste) -> {list.remove (o); Rückkehr list.isEmpty()? null: list;});' – Holger

+0

@Holger yep, Ich habe diese zwei Methoden überprüft, aber es ist der Fall - wir wissen nicht 'abwesend' oder 'anwesend', also habe ich entschieden, allgemeinere Methode' compute' zu ​​verwenden, die zwei Fälle zum Zeitpunkt deckt –

+1

Anscheinend Sie habe die Logik nicht verstanden. Sie müssen nicht wissen, ob der Schlüssel fehlt oder vorhanden ist, da diese Methoden das Richtige für Sie tun werden. Für den Fall 'populateMapWith' können Sie' computeIfAbsent (X, Schlüssel -> neue ArrayList <>()) 'verwenden, die entweder die existierende 'Liste' zurückgibt oder eine neue speichert und sie zurückgibt; In jedem Fall gibt es die richtige Liste zum Hinzufügen zurück. Für 'removeFromMap' ist der Fall noch einfacher, Sie können' computeIfPresent' verwenden, denn wenn der Schlüssel fehlt, gibt es nichts zu tun. – Holger

1
if(!getCarsMap().get(car.getModel()).contains(car)) 

Es scheint, dass Sie nicht wünschen, zu Duplikate haben. Also statt einer Liste, müssen Sie eine Set verwenden, die keine doppelten Elemente hinzufügt, wie:

Map<String, Set<Car>> carmap = getCarsMap(); 

getBoatsMap().put(car.getModel(), tmpList) ;

Das macht keinen Sinn. Ein Auto in eine Karte zu legen, die Boote haben soll, ist verwirrend. Allerdings gehe ich davon aus, damit zu gehen.

So können wir haben:

Set<Cars> tempcar = new HashSet<>(); 
tempcar.add(car); 
getBoatsMap().put(car.getModel(),tempcar); 

public Car addCar(Car car)

Der Rückgabetyp addCar Methode. Eine Methode gibt das Objekt zurück, das sie bearbeitet. Hier wird die Karte manipuliert und nicht das Objekt. Es sollte etwas sein wie:

public Map<String,Set<Car>> addCar(Car car) 

So können wir den folgenden Code haben:

public HashMap<String,Set<Car>> addCar(Car car){ 
     Map<String, Set<Car>> carmap = getCarsMap(); 
     if(carmap.containsKey(car.getModel())){ 
      HashSet<Car> carset = carmap.get(car.getModel()); 
      carset.add(car); 
      map.put(car.getModel(),carset); 
     }else{ 
      carmap = getBoatsMap(); 
      Set<Cars> tempcar = new HashSet<>(); 
      tempcar.add(car); 
      carmap.put(car.getModel(),tempcar); 
     } 
     return carmap; 
    } 

Dies kann die grundlegende Vorlage für Sie, sich zu bewegen. Dies kann jedoch auch weiter optimiert werden. Eine tiefere Untersuchung von Java Collections API und Java 8 kann Ihnen bessere Ideen liefern.

Denn removeCar() kann die Signatur der Methode sein:

public Car removeCar(Car) 

UPDATE ich in Kommentar, dass getBoatsMap() ein Fehler. So ist der Code:

public Map<String, Set<Car>> addCar(Car car){ 
    Map<String, Set<Car>> carmap = getCarsMap(); 
    if(carmap.containsKey(car.getModel())){ 
     HashSet<Car> carset = carmap.get(car.getModel()); 
     carset.add(car); 
     map.put(car.getModel(),carset); 
    }else{ 
     Set<Cars> tempcar = new HashSet<>(); 
     tempcar.add(car); 
     carmap.put(car.getModel(),tempcar); 
    } 
    return carmap; 
} 
+0

Sie sollten Ihre Meinung ... entweder 'HashMap >' oder 'Map >' (oder noch besser 'Map >'), aber beides zusammen funktioniert nicht. – Tom

+0

Ja, Sie haben Recht. Danke für das Aufzeigen! @Tom – Amita

+2

Sie müssen ein bereits in der Karte vorhandenes Mapping nicht erneut eingeben. Weiter '.add (Auto)' ist gemeinsamer Code, der in beiden Fällen ausgeführt wird.Der verbesserte Code lautet also: HashSet carset = carmap.get (car.getModel()); if (carset == null) {carmap.put (car.getModel(), carset = neuer HashSet <>()); } carset.add (Auto); '. Nun, wenn Sie an diesem Punkt sind, können Sie es mit der Macht von Java 8 verbessern: 'carmap.computeIfAbsent (car.getModel(), Schlüssel -> new HashSet <>()). Add (auto); die gleiche Logik, aber ist ein One-Liner ... – Holger

1

Die Spitzen:

  • Verwenden Set statt List weil Set keine Duplikate erlauben.

  • Verwenden contains zu überprüfen, ob ein Element in einer Sammlung ist, unabhängig davon, ob es ein List oder ein Set ist. (Car Klasse muss eine equals Methode, die die Feldwerte vergleicht.)

  • eine boolean Rückkehr, um anzuzeigen, wenn die Sammlung als Ergebnis der Operation geändert. Das machen Java-Sammlungen.

Der Code:

public boolean addCar(Car car) { 
    Map<String, Set<Car>> carsMap = getCarsMap(); 
    if (!carsMap.containsKey(car.getModel())) { 
     carsMap.put(car.getModel(), new HashSet<>(Arrays.asList(car))); 
     return true; 
    } 
    if (!carsMap.get(car.getModel()).contains(car)) { 
     return carsMap.get(car.getModel()).add(car); 
    } 
    return false; 
}