[JAVA] Convertir la carte <K, V1> en carte <K, V2> (Convertir la valeur de la carte)

Aperçu

Comment dois-je écrire lorsque je veux convertir des valeurs de Map () en une autre classe à la fois? Expliquons avec un exemple qui convertit Map <String, String> en Map <String, Integer>.

Plan de mise en œuvre

Proposition 1: Utilisation pour la déclaration

public Map<String, Integer> strToInt(final Map<String, String> map) {
    final Map<String, Integer> ret = new HashMap<>();
    for (final Map.Entry<String, String> entry : map.entrySet()) {
        ret.put(entry.getKey(), Integer.valueOf(entry.getValue()));
    }
    return ret;
}

Pour le moment, il a été écrit en Java 7. Il y a beaucoup de code redondant et non essentiel.

Option 2: utiliser l'API Java 8 Stream

public Map<String, Integer> strToInt(final Map<String, String> map) {
    return map.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, e -> Integer.valueOf(e.getValue())));
}

C'est plus court que le plan 1, mais c'est quand même un peu long.

Proposition 3: [Maps :: transformValues] de Guava (https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/collect/Maps.html#transformValues-java.util.Map- Utilisez com.google.common.base.Function-)

public Map<String, Integer> strToInt(final Map<String, String> map) {
    return Maps.transformValues(map, new Function<String, Integer>() {
        @Override
        public Integer apply(String input) {
            return Integer.valueOf(input);
        }
    });
}

cette? Est-ce plus long que le plan 2? Non, vous pouvez utiliser Expression Lambda car la méthode abstraite est une interface fonctionnelle.

public Map<String, Integer> strToInt(final Map<String, String> map) {
    return Maps.transformValues(map, v -> Integer.valueOf(v));
}

Vous pouvez également utiliser Reportez-vous à la méthode, afin de la raccourcir un peu.

public Map<String, Integer> strToInt(final Map<String, String> map) {
    return Maps.transformValues(map, Integer::valueOf);
}

Proposition 4: [Maps :: transformValues] de Guava (https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/collect/Maps.html#transformValues-java.util.Map- Une autre solution utilisant com.google.common.base.Function-)

public Map<String, Integer> strToInt(final Map<String, String> map) {
    return ImmutableMap.copyOf(Maps.transformValues(map, Integer::valueOf));
}

Proposition 3 avec ImmutableMap :: copyOf Enveloppé. L'explication sera décrite plus loin.

tester

Maintenant, testons si cela fonctionne correctement.

Classe testée

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

interface MapValuesTransformer {

    Map<String, Integer> strToInt(final Map<String, String> map);

    /**
     *Proposition 1:Utiliser pour la déclaration
     */
    static class ForImpl implements MapValuesTransformer {
        @Override
        public Map<String, Integer> strToInt(final Map<String, String> map) {
            final Map<String, Integer> ret = new HashMap<>();
            for (final Map.Entry<String, String> entry : map.entrySet()) {
                ret.put(entry.getKey(), Integer.valueOf(entry.getValue()));
            }
            return ret;
        }
    }

    /**
     *Proposition 2:Utiliser l'API Java 8 Stream
     */
    static class StreamImpl implements MapValuesTransformer {
        @Override
        public Map<String, Integer> strToInt(final Map<String, String> map) {
            return map.entrySet().stream()
                    .collect(Collectors.toMap(Map.Entry::getKey, e -> Integer.valueOf(e.getValue())));
        }
    }

    /**
     *Proposition 3:Cartes de goyave::Utiliser transformValues
     */
    static class TranformValuesImpl implements MapValuesTransformer {
        @Override
        public Map<String, Integer> strToInt(final Map<String, String> map) {
            return Maps.transformValues(map, Integer::valueOf);
        }
    }

    /**
     *Proposition 4:Cartes de goyave::Une autre solution utilisant transformValues
     */
    static class CopyOfTranformValuesImpl implements MapValuesTransformer {
        @Override
        public Map<String, Integer> strToInt(final Map<String, String> map) {
            return ImmutableMap.copyOf(Maps.transformValues(map, Integer::valueOf));
        }
    }

}

Squelette de code de test

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class MapValuesTramsformerTest {

    private final MapValuesTransformer transformer;

    public MapValuesTramsformerTest(MapValuesTransformer transformer) {
        this.transformer = transformer;
    }

    @Parameters(name = "{0}")
    public static Iterable<MapValuesTransformer> testClasses() {
        return Arrays.asList(
                new MapValuesTransformer.ForImpl(),
                new MapValuesTransformer.StreamImpl(),
                new MapValuesTransformer.TranformValuesImpl(),
                new MapValuesTransformer.CopyOfTranformValuesImpl()
        );
    }

    //Écrivez divers tests ici
}

Tester si la valeur a été convertie

@Test
public void La valeur est-elle convertie?() {
    Map<String, String> source = new HashMap<>();
    source.put("one", "1");
    source.put("zero", "0");
    source.put("min", "-2147483648");

    Map<String, Integer> expected = new HashMap<>();
    expected.put("one", 1);
    expected.put("zero", 0);
    expected.put("min", Integer.MIN_VALUE);

    // [Proposition 1: ForImpl] Passed
    // [Proposition 2: StreamImpl] Passed
    // [Proposition 3: TranformValuesImpl] Passed
    // [Proposition 4: CopyOfTranformValuesImpl] Passed
    assertThat(transformer.strToInt(source), is(expected));
}

Je l'ai passé en toute sécurité.

Tester si l'ordre est conservé

@Test
public void L'ordre est-il maintenu?() {
    Map<String, String> source = new LinkedHashMap<>();
    source.put("one", "1");
    source.put("zero", "0");
    source.put("min", "-2147483648");

    Map<String, Integer> transformed = transformer.strToInt(source);

    // [Proposition 1: ForImpl] Expected: is "[one, zero, min]" but: was "[zero, min, one]"
    // [Proposition 2: StreamImpl] Expected: is "[one, zero, min]" but: was "[zero, min, one]"
    // [Proposition 3: TranformValuesImpl] Passed
    // [Proposition 4: CopyOfTranformValuesImpl] Passed
    assertThat(transformed.keySet().toString(), is(source.keySet().toString()));
}

(Bien que ce soit un test approximatif pour suivre le résultat) Les plans 1 et 2 ont échoué.

Dans la mise en œuvre de Plan 1 et Plan 2, il devient HashMap, donc LinkedHashMap et [TreeMap](https://docs.oracle.com/javase/jp/8/ Si vous passez docs / api / java / util / TreeMap.html), la garantie de la commande est perdue.

Test immuable

@Test(expected = UnsupportedOperationException.class)
public void Immuable Est-ce immuable?() {
    Map<String, String> source = new HashMap<>();
    source.put("one", "1");

    Map<String, Integer> expected = new HashMap<>();
    expected.put("one", 1);

    Map<String, Integer> transformed = transformer.strToInt(source);

    // [Proposition 1: ForImpl] Failed
    // [Proposition 2: StreamImpl] Failed
    // [Proposition 3: TranformValuesImpl] Passed
    // [Proposition 4: CopyOfTranformValuesImpl] Passed
    transformed.put("two", 2);
}

Dans le cas du plan 3 et du plan 4, lorsque la méthode put de la carte convertie est appelée, [UnsupportedOperationException](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/UnsupportedOperationException] .html) est lancé.

Les propositions 1 et 2 étaient mutables et les propositions 3 et 4 étaient immuables.

Tester si la carte est copiée

@Test
La carte publique vide est-elle copiée?() {
    Map<String, String> source = new HashMap<>();
    source.put("one", "1");

    Map<String, Integer> expected = new HashMap<>();
    expected.put("one", 1);

    Map<String, Integer> transformed = transformer.strToInt(source);
    source.put("two", "2");

    // [Proposition 1: ForImpl] Passed
    // [Proposition 2: StreamImpl] Passed
    // [Proposition 3: TransformValuesImpl]: Expected: is <{one=1}> but: was <{one=1, two=2}>
    // [Proposition 4: CopyOfTranformValuesImpl] Passed
    assertThat(transformed, is(expected));
}

Uniquement lors de la mise en œuvre du plan 3, les modifications apportées à la carte source de conversion après la conversion ont été reflétées dans la carte de destination de la conversion.

Il s'agit de [JavaDoc for Maps :: transformValues](https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/collect/Maps.html#transformValues-java.util.Map- Comme décrit dans com.google.common.base.Function-), cette méthode "renvoie une vue de la carte".

Par conséquent, si vous souhaitez une copie (vous ne souhaitez pas refléter les modifications apportées à la carte source de conversion dans la destination de la conversion), ImmutableMap :: copyOf comme indiqué dans la proposition 4. Vous devez envelopper avec -jre / api / docs / com / google / common / collect / ImmutableMap.html # copyOf-java.util.Map-).

Résumé des résultats du test

Tester la perspective Proposition 1 Proposition 2 Proposition 3 Proposition 4
La valeur est-elle convertie? Yes Yes Yes Yes
L'ordre est-il maintenu? No No Yes Yes
Immutable(Immuable)Ou No No Yes Yes
La carte est-elle copiée? Yes Yes No Yes

Si vous connaissez les Avantages de l'immuabilité, la méthode de mise en œuvre de Plan 3 ou Plan 4 peut être meilleure. ?? Il paraît que.

URL de référence

Recommended Posts

Convertir la carte <K, V1> en carte <K, V2> (Convertir la valeur de la carte)
[Java] Convertir 1 en N liste en carte
[Core ML] Comment convertir YOLO v3 en Core ML
[Java] Convertit le code DB en valeur de code à l'aide d'énum
Comment utiliser Map
Comment utiliser la carte
Flux appris (je veux convertir la liste en carte <Integer, List>)
Comment utiliser Map
Pour les débutants Java: List, Map, Iterator / Array ... Comment convertir?
[Java] Comment utiliser Map
9 Correspond à la valeur de retour
Je veux convertir des caractères ...
Convertir le type String en type Timestamp
Convertir en chaîne Ruby Leet
Convertir un objet sérialisable en octet []
Comment utiliser Java Map
Conversion de ○ mois en ○ années ○ mois
Comment convertir la base Java
[Java] Convertir ArrayList en tableau
[Android] Convertissez Map en JSON à l'aide de GSON avec Kotlin et Java
Comment incrémenter la valeur de Map sur une ligne en Java