Wednesday, September 19th, 2007

Anonymous คลาสในจาวาคือคลาสที่เขียนแทรกขึ้นมาโดยไม่มีชื่อเลย เวลาเรียกใช้ปกติก็จะผ่าน interface หรือ abstract class ที่เป็นต้นแบบทำให้มีข้อจำกัดอยู่สองสามอย่างคือ 1. ไม่มี constructor เนื่องจากการสร้าง constructor ในจาวาต้องรู้ชื่อคลาส ซึ่งมันไม่มีในคลาสแบบนี้แล้วมันจะไปสร้างได้ยังไงหละจริงมะ 2. ไม่สามารถเพิ่ม method ได้เพราะถึงเพิ่มไปก็ไม่รู้จะเรียกใช้ยังไงภายหลัง แต่วันนี้ผมจะมาแก้ปัญหาข้อสองหละ เพราะถ้าจะหลีกเลี่ยงโดยไปสร้าง Inner คลาสก็รู้สึกมันจะเยอะเกินไปอีก ใช้แค่นิดเดียวเอง ทำไมต้องสร้างคลาสใหม่ที่มีชื่อด้วยจริงมะ

มาดูโจทย์ผมเลยละกัน คือผมจะสร้าง Map แบบพิเศษที่ key 1 key สามารถเก็บค่าได้หลายค่า และสามารถเอาค่ามาหา key กลับได้ ถ้าลองหาดู Structure แบบนี้ที่มีอยู่แล้วก็จะไปเจอของ Apache Common Collection แต่อันนั้นมันอยู่แยกกันระหว่าง BidirectionMap กับ MultiValueMap อ่ะก็เลยต้องหาทางรวมกันซะเอง แล้วก็เจอปัญหาที่ method ด้านล่างนี้แหละ

class MultiValueBidirectionHashMap extends MultiValueBidirectionMap {
...
public Set {
 entrySet() {
   return null;
 }
...
}

ตัว Map.Entry เป็น interface ที่ลองขุดๆ คุ้ยๆ ดูแล้วมันไม่มี implement ให้เรียกใช้ก็ต้องสร้าง implement ขึ้นมาเอง (จริงๆ อาจจะมีก็ได้ แค่ขี้เกียจเอา source ของ Collection มาเปิดดูอ่ะนะ :lol: ) แล้วก็ได้ผลลัพธ์ตามด้านล่าง

public Set {
 entrySet() {
  Set entrys = new HashSet();
  for (K key : _keys) {
    V valuesOfKey = values[key];
    // _values เป็น Collection ที่เก็บค่าทั้งหมดที่อิงกับ key ไว้
    for (V value : valuesOfKey) {
      entrys.add(new Map.Entry() {
        // implement interface method
        ...
 
        // method that use to set key
        public Map.Entry setKey(K key) {
         // set the key that user pass to class key
          ...
          return this;
        }
      }.setKey(key));
    }
  }
  return entrys;
}

แค่นี้ก็ได้ method สำหรับใส่ค่าลงไปเพิ่ม พร้อมยัดค่าเข้าไปโดยไม่ต้องสร้าง inner คลาสเพื่อมาเรียกภายหลังอีกแล้ว แต่ดูโค้ดแล้วอาจจะแปลกๆ หน่อยเท่านั้นเอง :lol:

ปอลอ. ช่วงนี้เขียนแต่จาวาพื้นๆ แฮะ แต่ framework ทั้งหลายแหล่ของจาวาเห็นแล้วมันชวนปวดหัวดีเหลือเกินนี่นา
ปอลอสอง. netbeans6 beta1 ออกแล้ววันนี้พร้อมกับฝั่ง eclipse ที่ PDT ก็ออกมาแล้วเช่นกัน เลยตัดสินใจไม่ถูกเลยจะใช้ IDE ตัวไหนดีเพราะชอบ netbeans ที่ตัวเล็กโคตรๆ (Java SE Edition 22 MB) เทียบกับ eclipse แล้วช่างใหญ่เทอะทะนัก เห้อ ลงใช้คู่กันเลยละกันเนอะ

Monday, September 10th, 2007

วันนี้เจอบั๊กแปลกๆ ที่ไม่คิดว่าจะเจอได้ในโค้ดงานที่ทำอยู่ สิ่งที่อาจเกิดขึ้นตามมาคือ memory leak ถ้าใช้ไม่ดี และมันก็เกิดกับ hash map ซะด้วย บั๊กที่ว่าคือ การเปลี่ยน hash code ของ object ใน key ของ hash map

สิ่งที่เกิดขึ้นเมื่อมีการเปลี่ยนแปลงก็คือ hash map จะไม่สามารถคืน object กลับมาได้หากนำ object นั้นไปใช้อ้างอิง ลองดูจาก code ด้านล่างละกัน

import java.util.HashSet;
 
class A {
	String _data;
 
	A(String data) {
		_data = data;
	}
 
	public int hashCode() {
		int hash = 0;
		for(int i:_data.getBytes()) {
			hash += i;
		}
		return hash;
	}
 
	public boolean equals(Object obj) {
		if (obj instanceof A)
			return ((A)obj)._data.equals(_data);
		else
			return super.equals(obj);
	}
}
 
public class Test {
 
	public static void main(String... args) {
		HashSet sampleSet = new HashSet();
 
		A a1 = new A("a1");
		A a2 = new A("a2");
		A a3 = new A("a3");
		sampleSet.add(a1);
		sampleSet.add(a2);
		sampleSet.add(a3);
 
		a3._data = "a4";
		System.out.println(sampleSet.contains(new A("a3")));
		System.out.println(sampleSet.contains(new A("a4")));
		System.out.println(sampleSet.contains(new A("a2")));
	}
}

ผลลัพธ์ที่ได้ก็คือ

llun@pluto:~/Desktop/Sample$ java Test
false
false
true

จากตัวอย่างด้านบน ถ้าเราเพิ่ม A(”a4″) เข้าไปใน hash set จะยังเพิ่มได้โดยไม่ทับ object เก่า เนื่องจาก object อยู่ในช่อง array คนละช่องกันใน hash set แต่จะไม่สามารถเอาตัวที่ซ่อนอยู่ออกมาได้เลยยกเว้นใช้ iterator ไล่เอาที่ละตัวออกมา ดังนั้น object ที่จะใส่ใน hash ทั้งหลายแหล่ของจาวาจึงต้องระวังในการ override method hashCode() เพราะคงนึกภาพกันออกถ้า เอา object ใส่ไปใน hash แล้ว hash code เปลี่ยนหลังจากที่ใส่ไปทุกครั้ง จะเกิดอะไรขึ้น ถ้าจะทำอย่างนั้น hash set จะไม่ต่างจาก array ธรรมดาเลย

ปอลอ. วันนี้ประชุม แล้วนึกขึ้นได้ว่าต้องเตรียมเสนอ Apache Lucene กับ Apache POI แต่ยังไม่ได้ลองเล่นหรือหาข้อมูลเลย แย่แล้ว
ปอลอสอง. OpenSUSE 10.3 ออกเดือนหน้าแล้ว เดี๊ยว count down รออีกรอบดีกว่า ส่วน Ubuntu 7.10 คงสั่งเอาจากคลับหละ (สั่งพร้อมเสื้อ :grin: )

Tuesday, August 14th, 2007

วันนี้เพื่อนถามมาว่า มีอะไรในจาวาที่เหมือน Template ในภาษาซีหรือป่าว ก็เลยนึกถึงสมัยเรียนขึ้นมาเลย ที่อาจารย์จับเทียบ Template กับ Generic ว่ามันต่างกันยังไง แล้วใช้ยังไง (ต่างกันยังไง จำไม่ได้แล้วหละ :lol: ) สำหรับประโยชน์ของมันที่ผมชอบมากที่สุดเลยก็คือ ไม่ต้องนั่งเปลี่ยน Type ให้ปวดหัววุ่นวายอีกแล้ว แถม ไม่ต้องกังวลกับ Class cast exception ด้วย (สมัยก่อนเวลาจะเก็บอะไรลง Collection แล้วเอาออกมาที ใช้ไปไกลๆ แล้วมักลืมว่าตัวเองเก็บอะไรเอาออกมาทีก็เจอประจำ)

ถ้าใครยังนึกไม่ออกก็ลองนึกถึงพวก Collection ทั้งหลายดูเช่น List<String>, Set<Integer> อะไรพวกนี้ ที่อยู่ใน <> นั่นแหละที่เรียกว่า Generic

มาดู code ตัวอย่างกันดีกว่า

class Test {
public T extends Comparable<T> max (T a, T b) {
if (a.compareTo(b) > 0)
return a;
else
return b;
}
public static void main(String... args) {
Test t = new Test();
int a = 0, b = 1;
System.out.println(t.max(a,b));
}
}

จาก code ด้านบนจะเห็นว่าการใช้ Generic แทบไม่ต่างจาก Template เลย แต่ Object ที่จะใส่เข้ามาได้ไช่ว่าจะเป็นอะไรก็ได้เหมือน Template แต่ถูกกำหนดด้วย extend ที่บอกว่า Object นั้นต้องถูกสร้างจาก Class ที่ extend มาจากอะไร
ว่าไปแล้วก็เรียนผ่านมาตั้งนานแล้ว ส่วนใหญ่ก็เอาแต่ใช้ไม่เคยสร้างเองก็เลยลืมๆ ไปบ้าง (ปกติใช้แต่ของคนอื่น พวก Collection อะแหละ) พอขุดมาอีกทีก็รู้สึก โอ้ว มันช่างมหัศจรรย์นัก ทำไมตอนเรียนไม่ค่อยรู้สึกอย่างนี้หว่า 555 จริงๆ ยังมีอีกหลายอย่างที่เพิ่มมาในจาวา 5 นะเนี๊ยะ ที่เคยพูดไปแล้วก่อนหน้านี้ ก็ Annotation เดี๊ยวเอามาลองเขียนให้หมดเลยดีกว่า เอแต่ จาวา 6 ออกมาแล้วนี่หว่า รู้สึกเท่าที่ใช้มารู้แต่ว่ามันเร็วขึ้น ยังไม่ค่อยได้เข้าไปดูด้านในจริงๆ เลยว่ามีอะไรเปลี่ยนไปมั่ง สงสัยต้องลองเอามาดูอย่างละเอียดหน่อยและ