การเติมค่าเดียวกันทุกตำแหน่งใน ListView ด้วย Collections.fill()
ตัวอย่างนี้สาธิตการใช้ Collections.fill() เพื่อแทนที่ข้อมูลทุกตัวใน ArrayList ด้วยค่าเดียวกัน (Fill) ก่อนแสดงใน ListView
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
สร้างโปรเจกต์ Android ใหม่ใน Android Studio
ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="ป้อนชื่อ" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<Button android:id="@+id/btnSave" android:text="บันทึก" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<Button android:id="@+id/btnRefresh" android:text="รีเฟรช" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp">
</ListView>
</LinearLayout>
ขั้นตอนที่ 3: MainActivity.java
package com.example.myapplication;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private EditText etName;
private ListView listView;
private ArrayAdapter<String> adapter;
private ArrayList<String> arrayList = new ArrayList<>();
private Set<String> uniqueSet = new HashSet<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = findViewById(R.id.etName);
listView = findViewById(R.id.listView);
findViewById(R.id.btnRefresh).setOnClickListener(v -> {
if (adapter != null) {
adapter.notifyDataSetChanged();
listView.invalidateViews();
listView.refreshDrawableState();
}
});
findViewById(R.id.btnSave).setOnClickListener(v -> {
String input = etName.getText().toString().trim();
if (!input.isEmpty()) {
uniqueSet.add(input);
arrayList.clear();
arrayList.addAll(uniqueSet);
// จุดสำคัญ: ใช้ Collections.fill() แทนที่ทุกตัวด้วยค่า "Sairam"
// หมายเหตุ: fill() จะทำงานต่อ List ที่มีขนาดคงที่ (fixed size) หรือมีข้อมูลอยู่แล้ว
// หาก ArrayList ว่างเปล่า fill() จะไม่ทำอะไร (size = 0)
if (!arrayList.isEmpty()) {
Collections.fill(arrayList, "Sairam");
}
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(adapter);
Toast.makeText(this, "บันทึกสำเร็จ (fill ทั้งหมดเป็น Sairam)", Toast.LENGTH_SHORT).show();
} else {
etName.setError("กรุณาป้อนชื่อ");
}
});
}
}
คำอธิบาย Collections.fill()
Collections.fill(list, obj);
- แทนที่ทุกองค์ประกอบใน List ด้วย
objที่ระบุ - ทำงาน in-place (แก้ไข List เดิม)
- ต้องการ List ที่มี size > 0 - หาก List ว่าง จะไม่ทำอะไร
- Time Complexity: O(n) | Space: O(1)
- List ต้องรองรับ
set(int index, E element)operation
ตัวอย่างการทำงาน
กรณีปกติ (มีข้อมูลอยู่แล้ว)
ArrayList<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
// list = [A, B, C, D]
Collections.fill(list, "X");
// list = [X, X, X, X] (ขนาดยังคงเป็น 4)
กรณี List ว่าง (No-op)
ArrayList<String> emptyList = new ArrayList<>();
// size = 0
Collections.fill(emptyList, "X");
// emptyList = [] (ยังคงว่าง - ไม่มี error แต่ไม่ทำอะไร)
กรณีต้องการสร้าง List ใหม่ขนาด n เต็มค่าเดียวกัน
// วิธีที่ 1: ใช้ Collections.nCopies (สร้าง List ใหม่)
List<String> filled = Collections.nCopies(5, "Sairam");
// [Sairam, Sairam, Sairam, Sairam, Sairam] - Immutable list
// วิธีที่ 2: ใช้ ArrayList constructor
ArrayList<String> list = new ArrayList<>(Collections.nCopies(5, "Sairam"));
// Mutable ArrayList
// วิธีที่ 3: Java 8+ Stream
List<String> list = Stream.generate(() -> "Sairam").limit(5).collect(Collectors.toList());
ในตัวอย่างโค้ด (Logic Flow)
- User ป้อนชื่อ → เพิ่มลง
uniqueSet (HashSet - ไม่ซ้ำ)
arrayList.clear() → arrayList.addAll(uniqueSet) → ArrayList มีข้อมูลไม่ซ้ำ
Collections.fill(arrayList, "Sairam") → แทนที่ทุกตัวเป็น "Sairam"
- แสดงใน ListView → ทุกแถวจะเป็น "Sairam"
กรณีการใช้งานจริง
- Reset/Initialize: ตั้งค่าเริ่มต้นให้ ArrayList (เช่น Default values)
- Clear Data: ล้างข้อมูลเก่า แทนด้วย Placeholder
- Testing/Mock: สร้างข้อมูลทดสอบจำนวนมากค่าเดียวกัน
- Game Board: รีเซ็ตกระดานเกม (Tic-tac-toe, Chess board)
- Buffer Reuse: ใช้ buffer ซ้ำโดย fill ค่าใหม่
ข้อควรระวัง
- Mutable List เท่านั้น: ไม่ทำงานกับ
Collections.unmodifiableList() หรือ Collections.nCopies() (immutable)
- Empty List = No-op: ต้องมีข้อมูลอย่างน้อย 1 ตัว ถึงจะ fill ได้
- Reference Equality: ทุกตำแหน่งจะชี้ไป Object เดียวกัน (Same reference)
- สำหรับ Immutable objects (String, Integer) ไม่เป็นปัญหา แต่ Mutable objects ต้องระวัง
ตัวอย่างปัญหา Reference Sharing
List<StringBuilder> list = new ArrayList<>(Arrays.asList(
new StringBuilder("A"), new StringBuilder("B"), new StringBuilder("C")
));
Collections.fill(list, new StringBuilder("X"));
// list = [X, X, X] แต่ทั้ง 3 ชี้ StringBuilder ตัวเดียวกัน!
list.get(0).append("Y");
// list = [XY, XY, XY] - เปลี่ยนทั้งหมด!
เปรียบเทียบ Methods สำหรับเติมค่า
ArrayList<String> emptyList = new ArrayList<>(); // size = 0 Collections.fill(emptyList, "X"); // emptyList = [] (ยังคงว่าง - ไม่มี error แต่ไม่ทำอะไร)
กรณีต้องการสร้าง List ใหม่ขนาด n เต็มค่าเดียวกัน
// วิธีที่ 1: ใช้ Collections.nCopies (สร้าง List ใหม่) List<String> filled = Collections.nCopies(5, "Sairam"); // [Sairam, Sairam, Sairam, Sairam, Sairam] - Immutable list // วิธีที่ 2: ใช้ ArrayList constructor ArrayList<String> list = new ArrayList<>(Collections.nCopies(5, "Sairam")); // Mutable ArrayList // วิธีที่ 3: Java 8+ Stream List<String> list = Stream.generate(() -> "Sairam").limit(5).collect(Collectors.toList());
ในตัวอย่างโค้ด (Logic Flow)
- User ป้อนชื่อ → เพิ่มลง
uniqueSet(HashSet - ไม่ซ้ำ) arrayList.clear()→arrayList.addAll(uniqueSet)→ ArrayList มีข้อมูลไม่ซ้ำCollections.fill(arrayList, "Sairam")→ แทนที่ทุกตัวเป็น "Sairam"- แสดงใน ListView → ทุกแถวจะเป็น "Sairam"
กรณีการใช้งานจริง
- Reset/Initialize: ตั้งค่าเริ่มต้นให้ ArrayList (เช่น Default values)
- Clear Data: ล้างข้อมูลเก่า แทนด้วย Placeholder
- Testing/Mock: สร้างข้อมูลทดสอบจำนวนมากค่าเดียวกัน
- Game Board: รีเซ็ตกระดานเกม (Tic-tac-toe, Chess board)
- Buffer Reuse: ใช้ buffer ซ้ำโดย fill ค่าใหม่
ข้อควรระวัง
- Mutable List เท่านั้น: ไม่ทำงานกับ
Collections.unmodifiableList()หรือCollections.nCopies()(immutable) - Empty List = No-op: ต้องมีข้อมูลอย่างน้อย 1 ตัว ถึงจะ fill ได้
- Reference Equality: ทุกตำแหน่งจะชี้ไป Object เดียวกัน (Same reference)
- สำหรับ Immutable objects (String, Integer) ไม่เป็นปัญหา แต่ Mutable objects ต้องระวัง
ตัวอย่างปัญหา Reference Sharing
List<StringBuilder> list = new ArrayList<>(Arrays.asList(
new StringBuilder("A"), new StringBuilder("B"), new StringBuilder("C")
));
Collections.fill(list, new StringBuilder("X"));
// list = [X, X, X] แต่ทั้ง 3 ชี้ StringBuilder ตัวเดียวกัน!
list.get(0).append("Y");
// list = [XY, XY, XY] - เปลี่ยนทั้งหมด!
เปรียบเทียบ Methods สำหรับเติมค่า
| Method | สร้าง List ใหม่ | แก้ไข List เดิม | รองรับ Empty List | Mutable Result |
|---|---|---|---|---|
| Collections.fill() | ไม่ | ใช่ ✓ | ไม่ (No-op) | ใช่ |
| Collections.nCopies() | ใช่ ✓ | ไม่ | ใช่ ✓ | ไม่ (Immutable) |
| Arrays.fill() | ไม่ (Array) | ใช่ (Array) | ใช่ ✓ | ใช่ |
| Stream.generate().limit() | ใช่ ✓ | ไม่ | ใช่ ✓ | ใช่ |
สรุป
Collections.fill() เหมาะสำหรับ การรีเซ็ตค่าใน List ที่มีอยู่แล้ว ขนาดคงที่ หากต้องการสร้าง List ใหม่ขนาดกำหนด ให้ใช้ Collections.nCopies() หรือ Stream API แทน