2016-05-17 5 views
10

Sto cercando di rielaborare alcuni dei miei metodi per renderli più concisi utilizzando Java 8, le cui nuove funzionalità sto cercando di assorbire lentamente.Riprogettazione del metodo per utilizzare Java 8 Map.computeIfAbsent() con eccezione generata

È un metodo con lo scopo di aggiungere uno value a Map<Key, Set<Value>>. Esistono tre possibilità:

  1. La chiave non esiste: viene aggiunta e ad essa è associata una nuova serie contenente il valore.
  2. La chiave esiste: il valore viene aggiunto al set esistente. Si noti che un set non sarà mai null, perché ho alcune condizioni preliminari per affrontarlo.
  3. La chiave esiste e il valore è già contenuto nel set: viene emesso un numero IllegalArgumentException.

Il codice che implementa questo comportamento è la seguente, e non fa uso di Java 8 caratteristiche:

public void addValue(Key key, Value value) { 
    // irrelevant preconditions... 

    Set<Value> valuesForKey = myMap.get(key); 
    if (valuesForKey != null && valuesForKey.contains(value)) 
     throw new IllegalArgumentException("Association exists already"); 

    if (valuesForKey == null) 
     myMap.put(key, new HashSet<Value>(Arrays.asList(value))); 
    else 
     valuesForKey.add(value); 
} 

Vorrei ridurre questo codice utilizzando Java 8 metodi come computeIfAbsent.

potessi riassumere l'ultimo if-else blocco, ma non posso andare oltre la ridondanza del valore impostato al quale key mappe ad avere già in recuperati Nell'effettuare i controlli di presupposto.

public void addValue(Key key, Value value) { 
    // irrelevant preconditions... 

    Set<Value> valuesForKey = myMap.get(key); 
    if (valuesForKey != null && valuesForKey.contains(value)) 
     throw new IllegalArgumentException("Association exists already"); 

    myMap.computeIfAbsent(key, v -> new HashSet<Value>()).add(value); 
} 

C'è comunque una possibilità di unire tutto ciò in un'unica istruzione?

+0

Mentre si può certamente fare in questo modo, si dovrebbe prendere in considerazione l'uso di un 'Multimap' (ad esempio da Guava). Avere una 'Mappa >' o 'Mappa >' è nel 99% dei casi d'uso un odore di design. – Landei

+0

@Landei, Secondo me non è proprio "odore di codice" dal momento che JDK non ha un multiset e uno potrebbe non voler inserire un'intera libreria solo per quell'unico utilizzo. È la soluzione più semplice disponibile in tali circostanze e i metodi 'compute *' e 'merge' del CHM rendono la giocoleria di quelle cose abbastanza dirette. – the8472

+0

A mio parere, le raccolte JDK sono in uno stato pietoso (ad esempio mancano collezioni immutabili utilizzabili) e io uso librerie come Guava per quasi tutti i progetti. Ho fatto l'esperienza che una volta che hai importato una lib come quella, troverai sempre più posti dove è utile. – Landei

risposta

11

È possibile sfruttare il fatto che il metodo add(element) restituirà true se il set non contiene l'elemento specificato. Se questa chiamata restituisce false, significa che l'elemento non è stato aggiunto perché era già presente. Pertanto, è possibile utilizzare:

public void addValue(Key key, Value value) { 
    boolean added = myMap.computeIfAbsent(key, k -> new HashSet<>()).add(value); 
    if (!added) { 
     throw new IllegalArgumentException("Association exists already"); 
    } 
} 
+0

Non si sarebbe la vera eccezione sottostante in questo modo. Francamente non so perché il calcolo non possa generare un'eccezione. Non c'è ragione per cui non possa. Non viene eseguito in un thread separato. – momomo

+0

@momomo Perché 'computeIfAbsent' genera un'eccezione? L'aggiunta di un elemento a un set già esistente non genera un'eccezione. – Tunaki

+0

Forse prima di aggiungerlo devi fare qualcosa, che potrebbe generare un'eccezione – momomo

Problemi correlati