java - والنصوص - ماذا بعد تعلم الجافا




كيف تتكاثر بشكل فعال على كل إدخال في خريطة جافا؟ (20)

إذا كان لدي كائن يقوم بتنفيذ واجهة Map في Java وأرغب في التكرار أكثر من كل زوج موجود داخلها ، فما هي الطريقة الأكثر فاعلية لخوض الخريطة؟

هل سيعتمد ترتيب العناصر على تنفيذ الخريطة المحدد الذي لدي على الواجهة؟


Lambda Expression Java 8

في Java 1.8 (Java 8) ، أصبح هذا أسهل كثيرًا باستخدام أسلوب forEach من عمليات التجميع ( عمليات الدفق ) التي تشبه المتكررات من واجهة Iterable .

فقط قم بنسخ المعطف أدناه إلى التعليمة البرمجية وإعادة تسمية متغير HashMap من hm إلى المتغير HashMap لطباعة زوج القيمة الرئيسية.

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
 *     Logic to put the Key,Value pair in your HashMap hm
 */

// Print the key value pair in one line.

hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));

// Just copy and paste above line to your code.

فيما يلي نموذج التعليمة البرمجية التي حاولت استخدام Lambda Expression . هذه الاشياء هي باردة جدا. يجب أن نحاول.

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
    Random rand = new Random(47);
    int i=0;
    while(i<5){
        i++;
        int key = rand.nextInt(20);
        int value = rand.nextInt(50);
        System.out.println("Inserting key: "+key+" Value: "+value);
        Integer imap =hm.put(key,value);
        if( imap == null){
            System.out.println("Inserted");
        }
        else{
            System.out.println("Replaced with "+imap);
        }               
    }

    hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));

Output:

Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11

أيضا يمكن للمرء أن يستخدم Spliterator لنفسه.

Spliterator sit = hm.entrySet().spliterator();

تحديث

بما في ذلك روابط الوثائق إلى Oracle Docs. لمعرفة المزيد عن لامبدا ، اذهب إلى هذا link ، ويجب أن تقرأ " العمليات التجميعية" و "Splitudeator" انتقل إلى هذا link .


FYI ، يمكنك أيضًا استخدام map.keySet() و map.values() إذا كنت مهتمًا فقط بالمفاتيح / قيم الخريطة وليس الآخر.


استخدم Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

الأكثر تعقيدا مع جافا 8:

map.entrySet().forEach(System.out::println);

الطريقة الصحيحة للقيام بذلك هي استخدام الإجابة المقبولة لأنها الأكثر كفاءة. أجد الرمز التالي يبدو أنظف قليلا.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}

باستخدام مجموعات Eclipse ( مجموعات GS سابقًا) ، ستستخدم أسلوب forEachKeyValue على واجهة MapIterable ، التي يتم توريثها بواسطة واجهات MutableMap و ImmutableMap وتطبيقاتها.

final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
    public void value(Integer key, String value)
    {
        result.add(key + value);
    }
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

باستخدام بنية Java 8 lambda ، يمكنك كتابة الكود كما يلي:

MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

ملاحظة: أنا ملتزم بمجموعات Eclipse.


في Java 8 لدينا طريقة forEach التي تقبل link . لدينا أيضا stream APIs. النظر في الخريطة:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

تكرار فوق مفاتيح:

sample.keySet().forEach((k) -> System.out.println(k));

تكرار على القيم:

sample.values().forEach((v) -> System.out.println(v));

تكرار فوق الإدخالات (باستخدام forEach و Streams):

sample.forEach((k,v) -> System.out.println(k + "=" + v)); 
sample.entrySet().stream().forEach((entry) -> {
            Object currentKey = entry.getKey();
            Object currentValue = entry.getValue();
            System.out.println(currentKey + "=" + currentValue);
        });

ميزة مع تدفقات أنها يمكن أن تكون متوازية بسهولة في حال كنا نريد. نحتاج ببساطة إلى استخدام parallelStream() بدلاً من stream() أعلاه.


في Java 8 يمكنك القيام بذلك بشكل نظيف وسريع باستخدام ميزات lambdas الجديدة:

 Map<String,String> map = new HashMap<>();
 map.put("SomeKey", "SomeValue");
 map.forEach( (k,v) -> [do something with key and value] );

 // such as
 map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));

سيتم استنتاج نوع k و v بواسطة المحول البرمجي وليس هناك حاجة لاستخدام Map.Entry بعد الآن.

سهل جدا!


لتلخيص الإجابات الأخرى ودمجها مع ما أعرفه ، وجدت 10 طرق رئيسية للقيام بذلك (انظر أدناه). أيضا ، كتبت بعض اختبارات الأداء (انظر النتائج أدناه). على سبيل المثال ، إذا أردنا العثور على مجموع جميع مفاتيح وقيم الخريطة ، فيمكننا كتابة:

  1. باستخدام المكرر و Map.Entry

    long i = 0;
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        i += pair.getKey() + pair.getValue();
    }
    
  2. باستخدام foreach و Map.Entry

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
    
  3. باستخدام forEach من Java 8

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
    
  4. باستخدام keySet و foreach

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    
  5. باستخدام keySet و iterator

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
    
  6. استخدام ل و Map.Entry

    long i = 0;
    for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        i += entry.getKey() + entry.getValue();
    }
    
  7. باستخدام Java 8 Stream API

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
    
  8. باستخدام Java 8 Stream API parallel

    final long[] i = {0};
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
    
  9. استخدام IterableMap من Apache Collections

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
    
  10. استخدام MutableMap من مجموعات Eclipse (CS)

    final long[] i = {0};
    mutableMap.forEachKeyValue((key, value) -> {
        i[0] += key + value;
    });
    

اختبارات برفومنس (mode = AverageTime ، system = Windows 8.1 64-bit ، Intel i7-4790 3.60 GHz ، 16 جيجابايت)

  1. بالنسبة إلى الخريطة الصغيرة (100 عنصر) ، فإن النتيجة 0.308 هي الأفضل

    Benchmark                          Mode  Cnt  Score    Error  Units
    test3_UsingForEachAndJava8         avgt  10   0.308 ±  0.021  µs/op
    test10_UsingEclipseMap             avgt  10   0.309 ±  0.009  µs/op
    test1_UsingWhileAndMapEntry        avgt  10   0.380 ±  0.014  µs/op
    test6_UsingForAndIterator          avgt  10   0.387 ±  0.016  µs/op
    test2_UsingForEachAndMapEntry      avgt  10   0.391 ±  0.023  µs/op
    test7_UsingJava8StreamApi          avgt  10   0.510 ±  0.014  µs/op
    test9_UsingApacheIterableMap       avgt  10   0.524 ±  0.008  µs/op
    test4_UsingKeySetAndForEach        avgt  10   0.816 ±  0.026  µs/op
    test5_UsingKeySetAndIterator       avgt  10   0.863 ±  0.025  µs/op
    test8_UsingJava8StreamApiParallel  avgt  10   5.552 ±  0.185  µs/op
    
  2. بالنسبة إلى الخريطة التي تحتوي على 10000 عنصر ، تكون النتيجة 37.606 هي الأفضل

    Benchmark                           Mode   Cnt  Score      Error   Units
    test10_UsingEclipseMap              avgt   10    37.606 ±   0.790  µs/op
    test3_UsingForEachAndJava8          avgt   10    50.368 ±   0.887  µs/op
    test6_UsingForAndIterator           avgt   10    50.332 ±   0.507  µs/op
    test2_UsingForEachAndMapEntry       avgt   10    51.406 ±   1.032  µs/op
    test1_UsingWhileAndMapEntry         avgt   10    52.538 ±   2.431  µs/op
    test7_UsingJava8StreamApi           avgt   10    54.464 ±   0.712  µs/op
    test4_UsingKeySetAndForEach         avgt   10    79.016 ±  25.345  µs/op
    test5_UsingKeySetAndIterator        avgt   10    91.105 ±  10.220  µs/op
    test8_UsingJava8StreamApiParallel   avgt   10   112.511 ±   0.365  µs/op
    test9_UsingApacheIterableMap        avgt   10   125.714 ±   1.935  µs/op
    
  3. بالنسبة إلى الخريطة التي تحتوي على 100000 عنصر ، تكون النتيجة 1184.767 هي الأفضل

    Benchmark                          Mode   Cnt  Score        Error    Units
    test1_UsingWhileAndMapEntry        avgt   10   1184.767 ±   332.968  µs/op
    test10_UsingEclipseMap             avgt   10   1191.735 ±   304.273  µs/op
    test2_UsingForEachAndMapEntry      avgt   10   1205.815 ±   366.043  µs/op
    test6_UsingForAndIterator          avgt   10   1206.873 ±   367.272  µs/op
    test8_UsingJava8StreamApiParallel  avgt   10   1485.895 ±   233.143  µs/op
    test5_UsingKeySetAndIterator       avgt   10   1540.281 ±   357.497  µs/op
    test4_UsingKeySetAndForEach        avgt   10   1593.342 ±   294.417  µs/op
    test3_UsingForEachAndJava8         avgt   10   1666.296 ±   126.443  µs/op
    test7_UsingJava8StreamApi          avgt   10   1706.676 ±   436.867  µs/op
    test9_UsingApacheIterableMap       avgt   10   3289.866 ±  1445.564  µs/op
    

الرسوم البيانية (اختبارات perfomance اعتماداً على حجم الخريطة)

جدول (اختبارات برفومنس تعتمد على حجم الخريطة)

          100     600      1100     1600     2100
test10    0.333    1.631    2.752    5.937    8.024
test3     0.309    1.971    4.147    8.147   10.473
test6     0.372    2.190    4.470    8.322   10.531
test1     0.405    2.237    4.616    8.645   10.707
test2     0.376    2.267    4.809    8.403   10.910
test7     0.473    2.448    5.668    9.790   12.125
test9     0.565    2.830    5.952   13.220   16.965
test4     0.808    5.012    8.813   13.939   17.407
test5     0.810    5.104    8.533   14.064   17.422
test8     5.173   12.499   17.351   24.671   30.403

جميع الاختبارات على GitHub .


مثال على استخدام المكرر والأدوية:

Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Map.Entry<String, String> entry = entries.next();
  String key = entry.getKey();
  String value = entry.getValue();
  // ...
}

من الناحية النظرية ، فإن الطريقة الأكثر فعالية تعتمد على تنفيذ الخريطة. الطريقة الرسمية للقيام بذلك هي استدعاء map.entrySet() ، والتي تقوم بإرجاع مجموعة Map.Entry ، يحتوي كل منها على مفتاح وقيمة ( entry.getKey() و entry.getValue() ).

في التطبيق الفقهي ، قد يحدث بعض الاختلاف فيما إذا كنت تستخدم map.keySet() أو map.entrySet() أو أي شيء آخر. لكنني لا أستطيع التفكير في سبب قيام أي شخص بكتابته على هذا النحو. على الأرجح أنه لا يوجد فرق في الأداء ما تفعله.

ونعم ، فإن الأمر يعتمد على التنفيذ - وكذلك (ربما) ترتيب الإدراج وغيرها من العوامل التي يصعب السيطرة عليها.

[تحرير] كتبت valueSet() الأصل ولكن بالطبع entrySet() هو في الواقع الجواب.


نعم ، يعتمد الأمر على تنفيذ الخريطة المحدد.

@ ScArcher2 لديه بنية جافا 1.5 الأكثر أناقة . في 1.4 ، سأفعل شيء من هذا القبيل:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

هناك عدة طرق للتكرار عبر الخريطة.

في ما يلي مقارنة بين أدائهم لمجموعة بيانات مشتركة مخزنة في الخريطة من خلال تخزين مليون من أزواج القيم الرئيسية في الخريطة وسيتم تكرارها على الخريطة.

1) باستخدام entrySet() في كل حلقة

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 ميلي ثانية

2) باستخدام keySet() في كل حلقة

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 ميلي ثانية

3) باستخدام entrySet() و iterator

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 ميلي ثانية

4) باستخدام keySet() و iterator

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 ميلي ثانية

لقد أشرت this link .


يمكنك القيام بذلك باستخدام الأدوية البديلة:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

سيعتمد الترتيب دائمًا على تنفيذ الخريطة المحدد. باستخدام جافا 8 يمكنك استخدام أي من هذه:

map.forEach((k,v) -> { System.out.println(k + ":" + v); });

أو:

map.entrySet().forEach((e) -> {
            System.out.println(e.getKey() + " : " + e.getValue());
        });

ستكون النتيجة هي نفسها (نفس الترتيب). و inputSet المدعومة من الخريطة بحيث تحصل على نفس الترتيب. الثاني سهل لأنه يسمح لك باستخدام lambdas ، على سبيل المثال إذا كنت ترغب فقط في طباعة كائنات عدد صحيح فقط أكبر من 5:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

يظهر الرمز أدناه التكرار من خلال LinkedHashMap و HashMap عادي (على سبيل المثال). سترى الاختلاف في الترتيب:

public class HMIteration {


    public static void main(String[] args) {
        Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
        Map<Object, Object> hashMap = new HashMap<>();

        for (int i=10; i>=0; i--) {
            linkedHashMap.put(i, i);
            hashMap.put(i, i);
        }

        System.out.println("LinkedHashMap (1): ");
        linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nLinkedHashMap (2): ");

        linkedHashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });


        System.out.println("\n\nHashMap (1): ");
        hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nHashMap (2): ");

        hashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });
    }
}

LinkedHashMap (1):

10 (# = 10): 10 ، 9 (# = 9): 9 ، 8 (# = 8): 8 ، 7 (# = 7): 7 ، 6 (# = 6): 6 ، 5 (# = 5 ): 5 ، 4 (# = 4): 4 ، 3 (# = 3): 3 ، 2 (# = 2): 2 ، 1 (# = 1): 1 ، 0 (# = 0): 0 ،

LinkedHashMap (2):

10: 10 ، 9: 9 ، 8: 8 ، 7: 7 ، 6: 6 ، 5: 5 ، 4: 4 ، 3: 3 ، 2: 2 ، 1: 1 ، 0: 0 ،

هاشماب (1):

0 (#: 0): 0، 1 (#: 1): 1، 2 (#: 2): 2، 3 (#: 3): 3، 4 (#: 4): 4، 5 (#: 5 ): 5 ، 6 (#: 6): 6 ، 7 (#: 7): 7 ، 8 (#: 8): 8 ، 9 (#: 9): 9 ، 10 (#: 10): 10 ،

هاشماب (2):

0: 0 ، 1: 1 ، 2: 2 ، 3: 3 ، 4: 4 ، 5: 5 ، 6: 6 ، 7: 7 ، 8: 8 ، 9: 9 ، 10: 10 ،


نعم ، كما يتفق الكثير من الناس أن هذا هو أفضل طريقة للتكرار أكثر من Map.

ولكن هناك فرص للرمي nullpointerexceptionإذا كانت الخريطة null. لا تنس أن تضع null.

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
}

           //Functional Oprations
            Map<String, String> mapString = new HashMap<>();
            mapString.entrySet().stream().map((entry) -> {
                String mapKey = entry.getKey();
                return entry;
            }).forEach((entry) -> {
                String mapValue = entry.getValue();
            });

            //Intrator
            Map<String, String> mapString = new HashMap<>();
            for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = it.next();
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();
            }

            //Simple for loop
            Map<String, String> mapString = new HashMap<>();
            for (Map.Entry<String, String> entry : mapString.entrySet()) {
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();

            }

    Iterator iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry element = (Map.Entry)it.next();
        LOGGER.debug("Key: " + element.getKey());
        LOGGER.debug("value: " + element.getValue());    
    }

Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet())
{
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    }
}




iteration