0Pricing
Java Academy · บทเรียน

toMap, joining และ summarizing

แปลงสตรีมเป็นแผนที่ ต่อสตริงด้วย joining และคำนวณสถิติด้วย summarizingInt

toMap, joining และ summarizing เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

พื้นฐานของ Collectors.toMap

Collectors.toMap(keyMapper, valueMapper) แปลงสตรีมเป็น Map โดยแต่ละองค์ประกอบจะให้คู่คีย์-ค่า 1 คู่

import java.util.*;
import java.util.stream.*;

record Country(String code, String name) {}
List<Country> countries = List.of(
    new Country("US","United States"),
    new Country("DE","Germany"),
    new Country("JP","Japan")
);

Map<String, String> codeToName =
    countries.stream().collect(
        Collectors.toMap(Country::code, Country::name)
    );
System.out.println(codeToName.get("DE")); // Germany

การจัดการคีย์ซ้ำ

toMap จะโยน IllegalStateException เมื่อพบคีย์ซ้ำ ให้ส่งฟังก์ชัน merge เป็นอาร์กิวเมนต์ตัวที่สามเพื่อจัดการข้อขัดแย้ง:

List<String> words = List.of("apple","ant","banana","bat","cherry");

Map<Character, String> firstByLetter =
    words.stream().collect(
        Collectors.toMap(
            w -> w.charAt(0),
            w -> w,
            (existing, replacement) -> existing // keep first
        )
    );
System.out.println(firstByLetter); // {a=apple, b=banana, c=cherry}

การใช้ toMap กับการแปลงค่า

ตัวแปลงค่าสามารถเป็นฟังก์ชันใดก็ได้ เพื่อแปลงองค์ประกอบก่อนจัดเก็บ:

record User(String login, String email) {}
List<User> users = List.of(
    new User("alice","alice@example.com"),
    new User("bob","bob@example.com")
);

Map<String, String> loginToEmail =
    users.stream().collect(
        Collectors.toMap(User::login, u -> u.email().toUpperCase())
    );
System.out.println(loginToEmail.get("alice")); // ALICE@EXAMPLE.COM

toUnmodifiableMap

ใช้ Collectors.toUnmodifiableMap() เพื่อสร้างแมปที่แก้ไขไม่ได้ ซึ่งเทียบเท่ากับการห่อด้วย Collections.unmodifiableMap() แต่เขียนได้สะอาดกว่า:

Map<String, Integer> wordLengths =
    Stream.of("Java","Stream","API")
          .collect(Collectors.toUnmodifiableMap(w -> w, String::length));
// wordLengths.put("test",4); // throws UnsupportedOperationException

Collectors.joining

Collectors.joining() นำองค์ประกอบสตริงมาต่อกัน โดยรับตัวคั่น คำนำหน้า และคำต่อท้ายเป็นอาร์กิวเมนต์เสริม:

List<String> names = List.of("Alice","Bob","Carol");

System.out.println(names.stream().collect(Collectors.joining()));
// AliceBobCarol

System.out.println(names.stream().collect(Collectors.joining(", ")));
// Alice, Bob, Carol

System.out.println(names.stream().collect(Collectors.joining(", ", "[", "]")));
// [Alice, Bob, Carol]

joining สำหรับผลลัพธ์ CSV

สร้างแถว CSV หรือส่วนคำสั่ง SQL IN ด้วย joining:

List<Integer> ids = List.of(1,2,3,4,5);

String inClause = ids.stream()
    .map(Object::toString)
    .collect(Collectors.joining(",", "(", ")"));
System.out.println("WHERE id IN " + inClause);
// WHERE id IN (1,2,3,4,5)

summarizingInt / แบบจำนวนเต็มยาว / แบบทศนิยมคู่

Collectors.summarizingInt() คำนวณสถิติทั้งหมดในการส่งผ่านครั้งเดียว และคืนค่าเป็น IntSummaryStatistics:

record Product(String name, int price) {}
List<Product> products = List.of(
    new Product("A",100), new Product("B",200), new Product("C",150)
);

IntSummaryStatistics stats =
    products.stream().collect(Collectors.summarizingInt(Product::price));

System.out.println("Count: " + stats.getCount());   // 3
System.out.println("Sum: "   + stats.getSum());     // 450
System.out.println("Min: "   + stats.getMin());     // 100
System.out.println("Max: "   + stats.getMax());     // 200
System.out.println("Avg: "   + stats.getAverage()); // 150.0

summingInt และ averagingInt

สำหรับกรณีง่าย ๆ ที่ต้องการสถิติเพียงรายการเดียว:

int total = products.stream().collect(Collectors.summingInt(Product::price));
System.out.println("Total: " + total); // 450

double avg = products.stream().collect(Collectors.averagingInt(Product::price));
System.out.println("Average: " + avg); // 150.0

การใช้ groupingBy กับ summarizingInt

รวมการสรุปข้อมูลแยกตามกลุ่ม:

record Sale(String region, int amount) {}
List<Sale> sales = List.of(
    new Sale("North",100), new Sale("South",200),
    new Sale("North",150), new Sale("South",300)
);

Map<String, IntSummaryStatistics> statsByRegion =
    sales.stream().collect(
        Collectors.groupingBy(Sale::region,
            Collectors.summarizingInt(Sale::amount))
    );
statsByRegion.forEach((r,s) ->
    System.out.printf("%s: sum=%d avg=%.1f%n", r, s.getSum(), s.getAverage()));

การรวบรวมเป็น LinkedHashMap

โดยค่าเริ่มต้น toMap จะสร้าง HashMap ที่ไม่รับประกันลำดับ ใช้รูปแบบที่รับอาร์กิวเมนต์ 4 ตัวเพื่อระบุ LinkedHashMap และรักษาลำดับการแทรก:

Map<String, Integer> ordered =
    Stream.of("banana","apple","cherry")
          .collect(Collectors.toMap(
              w -> w,
              String::length,
              (a,b) -> a,
              LinkedHashMap::new
          ));
System.out.println(ordered.keySet()); // [banana, apple, cherry]

ภาคปฏิบัติ: ตัวแยกวิเคราะห์การกำหนดค่า

แยกวิเคราะห์บรรทัดในรูปแบบ key=value เป็นแมปด้วย toMap:

List<String> lines = List.of("host=localhost","port=5432","db=myapp");

Map<String, String> config =
    lines.stream()
         .map(l -> l.split("=", 2))
         .collect(Collectors.toMap(a -> a[0], a -> a[1]));

System.out.println(config.get("port")); // 5432

ตรวจสอบความเข้าใจ

คุณใช้ Collectors.toMap(k, v) กับสตรีมที่มีองค์ประกอบสองรายการใช้คีย์เดียวกัน จะเกิดอะไรขึ้น

สรุป: toMap, joining และ summarizing

ประเด็นสำคัญ:

  • toMap(keyMapper, valueMapper) จะโยนข้อผิดพลาดเมื่อมีคีย์ซ้ำ หากไม่มีฟังก์ชัน merge
  • joining(ตัวคั่น, คำนำหน้า, คำต่อท้าย) นำสตริงมาต่อกันได้อย่างกระชับ
  • summarizingInt ให้จำนวน ผลรวม ค่าต่ำสุด ค่าสูงสุด และค่าเฉลี่ยในการส่งผ่านครั้งเดียว
  • ใช้ summingInt/averagingInt เมื่อต้องการสถิติเพียงรายการเดียว
  • ใช้ toMap แบบ 4 อาร์กิวเมนต์ร่วมกับ LinkedHashMap::new เพื่อให้ได้ผลลัพธ์ตามลำดับ

คำถามที่พบบ่อย

บทเรียน “toMap, joining และ summarizing” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “toMap, joining และ summarizing” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “toMap, joining และ summarizing”

แปลงสตรีมเป็นแผนที่ ต่อสตริงด้วย joining และคำนวณสถิติด้วย summarizingInt คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “toMap, joining และ summarizing” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. groupingBy: การจัดหมวดหมู่องค์ประกอบ
  2. partitioningBy และ counting
  3. toMap, joining และ summarizing
  4. การสร้าง Collector แบบกำหนดเอง
← กลับไปที่ Java Academy