对Java中匿名类的一些思考

引言

Java中的匿名类是比较有意思的一种编程方式,在swing中关于监听器的注册时,经常可见到这样的代码:

Java代码 复制代码
  1. iexit.addActionListener(new ActionListener(){   
  2.     public void actionPerformed(ActionEvent e) {   
  3.         int y = JOptionPane.showConfirmDialog(   
  4.                 null,    
  5.                 "Confirm exit",    
  6.                 "Confirm Exit Dialog",    
  7.                 JOptionPane.YES_NO_OPTION);   
  8.         if(y == JOptionPane.YES_OPTION){System.exit(0);}   
  9.     }   
  10. });  
		iexit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				int y = JOptionPane.showConfirmDialog(
						null, 
						"Confirm exit", 
						"Confirm Exit Dialog", 
						JOptionPane.YES_NO_OPTION);
				if(y == JOptionPane.YES_OPTION){System.exit(0);}
			}
		});

 通常使用匿名类的场景是,临时的创建一个类,实现指定的接口 ,使得调用者可以通过接口的方法来实现一定的操作。比如上边这个例子中,exit这个菜单项,需要一个动作监听器,如果用常规写法,大概如此:

Java代码 复制代码
  1. class XListener implements ActionListener{   
  2.     public void actionPerformed(ActionEvent e){   
  3.         //action here   
  4.     }   
  5. }   
  6. XListener l = new XListener();   
  7. iexit.addActionListener(l);  
	class XListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			//action here
		}
	}
	XListener l = new XListener();
	iexit.addActionListener(l);

虽然完成了同样的工作,但是代码量明显比刚才要多。

实例

在javascript,或者其他函数式编程语言中,常常可以见到诸如此类的写法:

Js代码 复制代码
  1. $("#element").click(function(){   
  2.     //do something   
  3. });   
  4.   
  5. $("div.type").each(function(index){   
  6.     //do something else with the index   
  7. });  
$("#element").click(function(){
	//do something
});

$("div.type").each(function(index){
	//do something else with the index
});

 将一个匿名函数传递给另一个函数,实现一些列定制的动作,正好工作中有个地方要用到类似的东东,就用java的匿名类实现了一套类似的机制:

Java代码 复制代码
  1. Integer[] is = new Integer[]{   
  2.     4,13,65,64,2,4,5,9,10,25,20,32,30  
  3. };   
  4.   
  5. //用数组构造一个integer 的 list   
  6. FPList<Integer> p = new FPList<Integer>(is);   
  7. p.append(100);//再添加一个元素   
  8.   
  9. //做一次过滤,只有偶数被留下来   
  10. FPList<Integer> even = p.filter(new Filter(){   
  11.     public boolean isLegal(Object item) {   
  12.         int x = ((Integer)item).intValue();   
  13.         return x % 2 == 0 ? true : false;   
  14.     }   
  15. }).filter(new Filter(){//再做一次过滤,10的倍数被留下来   
  16.     public boolean isLegal(Object item){   
  17.         int x = ((Integer)item).intValue();   
  18.         return x % 10 == 0 ? true : false;   
  19.     }   
  20. });  
		Integer[] is = new Integer[]{
			4,13,65,64,2,4,5,9,10,25,20,32,30
		};
		
		//用数组构造一个integer 的 list
		FPList<Integer> p = new FPList<Integer>(is);
		p.append(100);//再添加一个元素
		
		//做一次过滤,只有偶数被留下来
		FPList<Integer> even = p.filter(new Filter(){
			public boolean isLegal(Object item) {
				int x = ((Integer)item).intValue();
				return x % 2 == 0 ? true : false;
			}
		}).filter(new Filter(){//再做一次过滤,10的倍数被留下来
			public boolean isLegal(Object item){
				int x = ((Integer)item).intValue();
				return x % 10 == 0 ? true : false;
			}
		});

 这样可以将很多的条件AND到一起,对数据做条件过滤。

设计与实现

首先,需要定义一个接口(这是匿名类的基础),在这个例子中,我定义了一个过滤器接口,其中只有一个方法,即isLegal(Object item), 这个方法接受一个Obejct参数,返回一个boolean值,调用者根据这个boolean值来对最终结果做过滤:

Java代码 复制代码
  1. package org.free.fplist;   
  2.   
  3. /**  
  4.  * defined what condition should be used in <code>FilterableList.filter()</code>  
  5.  *   
  6.  * @author juntao.qiu@gmail.com  
  7.  *  
  8.  */  
  9. public interface Filter {   
  10.     /**  
  11.      * this is a condition definition, pass a object in, and then  
  12.      * a <code>true</code> or <code>false</code> will be returned.  
  13.      * @param item  
  14.      * @return  
  15.      */  
  16.     boolean isLegal(Object item);   
  17. }  
package org.free.fplist;

/**
 * defined what condition should be used in <code>FilterableList.filter()</code>
 * 
 * @author juntao.qiu@gmail.com
 *
 */
public interface Filter {
	/**
	 * this is a condition definition, pass a object in, and then
	 * a <code>true</code> or <code>false</code> will be returned.
	 * @param item
	 * @return
	 */
	boolean isLegal(Object item);
}

 另外,我们需要一个接口,用来表示一个链表具有被过滤的能力(FPable):

Java代码 复制代码
  1. package org.free.fplist;   
  2.   
  3. /**  
  4.  * This is the interface defined Function-programmable support  
  5.  *   
  6.  * @author juntao.qiu@gmail.com  
  7.  *  
  8.  */  
  9. public interface FPable<E> {   
  10.     /**  
  11.      * append a new element to list, and then return <code>this</code> object  
  12.      *   
  13.      * @param e element you want to insert into  
  14.      * @return  
  15.      */  
  16.     FPable<E> append(E e);   
  17.        
  18.     /**  
  19.      * do a filter by the given rule, the <code>Filter</code>  
  20.      * object passed in is defined as a interface, and you need  
  21.      * to implement the condition.  
  22.      *   
  23.      * @param f  
  24.      * @return  
  25.      */  
  26.     FPable<E> filter(Filter f);   
  27.        
  28.     /**  
  29.      * mapping the action to each item of <code>function-programming-list</code>  
  30.      * and will not affect the original list  
  31.      *   
  32.      * @param act the Action will used to mapping  
  33.      * @return  
  34.      */  
  35.     FPable<E> mapping(Action act);   
  36.        
  37.     /**  
  38.      * distinct the <code>FilterableList</code>, keep one same elements only, and  
  39.      * does not affect the List itself.  
  40.      *   
  41.      * @return  
  42.      */  
  43.     FPable<E> distinct();   
  44.        
  45.     /**  
  46.      * for debug only, print the <code>index</code> and <code>content</code>   
  47.      * of each item of a list.  
  48.      */  
  49.     void print();   
  50. }  
package org.free.fplist;

/**
 * This is the interface defined Function-programmable support
 * 
 * @author juntao.qiu@gmail.com
 *
 */
public interface FPable<E> {
	/**
	 * append a new element to list, and then return <code>this</code> object
	 * 
	 * @param e element you want to insert into
	 * @return
	 */
	FPable<E> append(E e);
	
	/**
	 * do a filter by the given rule, the <code>Filter</code>
	 * object passed in is defined as a interface, and you need
	 * to implement the condition.
	 * 
	 * @param f
	 * @return
	 */
	FPable<E> filter(Filter f);
	
	/**
	 * mapping the action to each item of <code>function-programming-list</code>
	 * and will not affect the original list
	 * 
	 * @param act the Action will used to mapping
	 * @return
	 */
	FPable<E> mapping(Action act);
	
	/**
	 * distinct the <code>FilterableList</code>, keep one same elements only, and
	 * does not affect the List itself.
	 * 
	 * @return
	 */
	FPable<E> distinct();
	
	/**
	 * for debug only, print the <code>index</code> and <code>content</code> 
	 * of each item of a list.
	 */
	void print();
}

 附加的,我需要对这个链表有函数映射 (map)的支持,上面这个接口中的Action,为另一个接口,同样会被很多的匿名类使用到:

Java代码 复制代码
  1. package org.free.fplist;   
  2.   
  3. public interface Action {   
  4.     public Object doAction(Object item);   
  5. }  
package org.free.fplist;

public interface Action {
	public Object doAction(Object item);
}

 

好了,我们现在来看一个FPable的实现FPList,FPList继承了LinkedList,并且实现了FPable,可以对其中的数据进行过滤(前提是传入一个过滤器 ),或者对其中的元素进行映射(传入一个动作 ),FPList会自动的将过滤器和动作作用到List中的每一个元素。

 

Java代码 复制代码
  1. package org.free.fplist;   
  2.   
  3. import java.util.HashSet;   
  4. import java.util.Iterator;   
  5. import java.util.LinkedList;   
  6. import java.util.Set;   
  7.   
  8. public class FPList<E> extends LinkedList<E> implements FPable<E>{   
  9.     private static final long    
  10.     serialVersionUID = 348375840291148300L;   
  11.   
  12.     public FPList(){   
  13.            
  14.     }   
  15.        
  16.     /**  
  17.      * construct a fp-list by given array.  
  18.      *   
  19.      * @param es  
  20.      */  
  21.     public FPList(E[] es){   
  22.         for(int i = 0;i < es.length;i++){   
  23.             add(es[i]);   
  24.         }   
  25.     }   
  26.        
  27.     public FPList<E> filter(Filter f){   
  28.         FPList<E> filtered = new FPList<E>();   
  29.         for(int i = 0; i < size();i++){   
  30.             E o = get(i);   
  31.             if(f.isLegal(o)){   
  32.                 filtered.add(o);   
  33.             }   
  34.         }   
  35.         return filtered;   
  36.     }   
  37.        
  38.     public FPList<E> append(E e){   
  39.         add(e);   
  40.         return this;   
  41.     }   
  42.        
  43.     public FPList<E> distinct(){   
  44.         FPList<E> filtered = this;   
  45.         Set<E> set = new HashSet<E>();   
  46.         for(int i = 0; i < filtered.size();i++){   
  47.             set.add(filtered.get(i));   
  48.         }   
  49.         filtered.clear();   
  50.         Iterator<E> it = set.iterator();   
  51.         while(it.hasNext()){   
  52.             filtered.add(it.next());   
  53.         }   
  54.         return filtered;   
  55.     }   
  56.        
  57.     public FPList<E> mapping(Action act){   
  58.         FPList<E> mapped = this;   
  59.         for(int i = 0;i < size();i++){   
  60.             mapped.add(i, (E)act.doAction(get(i)));   
  61.             mapped.remove(i+1);   
  62.         }   
  63.         return mapped;   
  64.     }   
  65.   
  66.     public void print(){   
  67.         for(int i = 0;i < size();i++){   
  68.             System.err.println("index : "+i+", content : "+get(i));   
  69.         }   
  70.     }   
  71. }  
package org.free.fplist;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

public class FPList<E> extends LinkedList<E> implements FPable<E>{
	private static final long 
	serialVersionUID = 348375840291148300L;

	public FPList(){
		
	}
	
	/**
	 * construct a fp-list by given array.
	 * 
	 * @param es
	 */
	public FPList(E[] es){
		for(int i = 0;i < es.length;i++){
			add(es[i]);
		}
	}
	
	public FPList<E> filter(Filter f){
		FPList<E> filtered = new FPList<E>();
		for(int i = 0; i < size();i++){
			E o = get(i);
			if(f.isLegal(o)){
				filtered.add(o);
			}
		}
		return filtered;
	}
	
	public FPList<E> append(E e){
		add(e);
		return this;
	}
	
	public FPList<E> distinct(){
		FPList<E> filtered = this;
		Set<E> set = new HashSet<E>();
		for(int i = 0; i < filtered.size();i++){
			set.add(filtered.get(i));
		}
		filtered.clear();
		Iterator<E> it = set.iterator();
		while(it.hasNext()){
			filtered.add(it.next());
		}
		return filtered;
	}
	
	public FPList<E> mapping(Action act){
		FPList<E> mapped = this;
		for(int i = 0;i < size();i++){
			mapped.add(i, (E)act.doAction(get(i)));
			mapped.remove(i+1);
		}
		return mapped;
	}

	public void print(){
		for(int i = 0;i < size();i++){
			System.err.println("index : "+i+", content : "+get(i));
		}
	}
}

使用匿名类

匿名类的使用是比较方便的,为了代码更简洁,我使用了jQuery中的链机制,其实,大家平时使用的StringBuffer就提供这样的能力。

 

Java代码 复制代码
  1. package org.free.fplist;   
  2.   
  3. public class Main {   
  4.     public static void main(String[] args){   
  5.         String[] as = new String[]{   
  6.                 "Apple",   
  7.                 "Borland",   
  8.                 "Cisco",   
  9.                 "Dell",   
  10.                 "Epson",   
  11.                 "Flick",   
  12.                 "Google"  
  13.         };   
  14.            
  15.         FPList<String> k = new FPList<String>(as);   
  16.            
  17.         k.distinct().filter(new Filter(){   
  18.             public boolean isLegal(Object item) {   
  19.                 return ((String)item).indexOf("e") >= 0 ? true : false;   
  20.             }   
  21.         }).filter(new Filter(){   
  22.             public boolean isLegal(Object item) {   
  23.                 return ((String)item).indexOf("p") >= 0 ?  true : false;   
  24.             }   
  25.         }).mapping(new Action(){   
  26.             public Object doAction(Object item) {   
  27.                 return ((String)item)+", co";   
  28.             }   
  29.         }).print();   
  30.            
  31.         Integer[] is = new Integer[]{   
  32.             4,13,65,64,2,4,5,9,10,25,20,32,30  
  33.         };   
  34.            
  35.         FPList<Integer> p = new FPList<Integer>(is);   
  36.         p.append(100);   
  37.            
  38.         FPList<Integer> even = p.filter(new Filter(){   
  39.             public boolean isLegal(Object item) {   
  40.                 int x = ((Integer)item).intValue();   
  41.                 return x % 2 == 0 ? true : false;   
  42.             }   
  43.         }).filter(new Filter(){   
  44.             public boolean isLegal(Object item){   
  45.                 int x = ((Integer)item).intValue();   
  46.                 return x % 10 == 0 ? true : false;   
  47.             }   
  48.         });   
  49.            
  50.         even.mapping(new Action(){   
  51.             public Object doAction(Object item) {   
  52.                 return ((Integer)item).intValue()*10;   
  53.             }   
  54.         }).mapping(new Action(){   
  55.             public Object doAction(Object item){   
  56.                 return ((Integer)item).intValue()/2;   
  57.             }   
  58.         }).print();   
  59.            
  60.         Person[] person = new Person[]{   
  61.             new Person("abruzzi"25"male"),   
  62.             new Person("smith"25"female"),   
  63.             new Person("json"26"female"),   
  64.             new Person("jet.lee"25"male")   
  65.         };   
  66.            
  67.         FPList<Person> fp = new FPList<Person>(person);   
  68.         fp.filter(new Filter(){   
  69.             public boolean isLegal(Object item) {   
  70.                 Person p = (Person)item;   
  71.                 return p.getAge() == 25 ? true : false;   
  72.             }   
  73.         }).filter(new Filter(){   
  74.             public boolean isLegal(Object item) {   
  75.                 Person p = (Person)item;   
  76.                 return p.getSex().equals("male") ? true : false;   
  77.             }   
  78.         }).mapping(new Action(){   
  79.             public Object doAction(Object item) {   
  80.                 System.err.println(((Person)item).getName());   
  81.                 return null;   
  82.             }   
  83.         });   
  84.   
  85.     }   
  86. }  
package org.free.fplist;

public class Main {
	public static void main(String[] args){
		String[] as = new String[]{
				"Apple",
				"Borland",
				"Cisco",
				"Dell",
				"Epson",
				"Flick",
				"Google"
		};
		
		FPList<String> k = new FPList<String>(as);
		
		k.distinct().filter(new Filter(){
			public boolean isLegal(Object item) {
				return ((String)item).indexOf("e") >= 0 ? true : false;
			}
		}).filter(new Filter(){
			public boolean isLegal(Object item) {
				return ((String)item).indexOf("p") >= 0 ?  true : false;
			}
		}).mapping(new Action(){
			public Object doAction(Object item) {
				return ((String)item)+", co";
			}
		}).print();
		
		Integer[] is = new Integer[]{
			4,13,65,64,2,4,5,9,10,25,20,32,30
		};
		
		FPList<Integer> p = new FPList<Integer>(is);
		p.append(100);
		
		FPList<Integer> even = p.filter(new Filter(){
			public boolean isLegal(Object item) {
				int x = ((Integer)item).intValue();
				return x % 2 == 0 ? true : false;
			}
		}).filter(new Filter(){
			public boolean isLegal(Object item){
				int x = ((Integer)item).intValue();
				return x % 10 == 0 ? true : false;
			}
		});
		
		even.mapping(new Action(){
			public Object doAction(Object item) {
				return ((Integer)item).intValue()*10;
			}
		}).mapping(new Action(){
			public Object doAction(Object item){
				return ((Integer)item).intValue()/2;
			}
		}).print();
		
		Person[] person = new Person[]{
			new Person("abruzzi", 25, "male"),
			new Person("smith", 25, "female"),
			new Person("json", 26, "female"),
			new Person("jet.lee", 25, "male")
		};
		
		FPList<Person> fp = new FPList<Person>(person);
		fp.filter(new Filter(){
			public boolean isLegal(Object item) {
				Person p = (Person)item;
				return p.getAge() == 25 ? true : false;
			}
		}).filter(new Filter(){
			public boolean isLegal(Object item) {
				Person p = (Person)item;
				return p.getSex().equals("male") ? true : false;
			}
		}).mapping(new Action(){
			public Object doAction(Object item) {
				System.err.println(((Person)item).getName());
				return null;
			}
		});

	}
}

main的运行结果如下:

 

index : 0, content : Apple, co
index : 0, content : 50
index : 1, content : 100
index : 2, content : 150
index : 3, content : 500
abruzzi
jet.lee

 

上边的例子显示,匿名类在接口 中的方法不多的时候,整个匿名类整体作为一个对象传递给另外一个方法,可以很好的做到可定制性。比如第三个例子,使用Person bean的时候,可以定制多个过滤条件,依次将原始列表过滤成一个符合要求的列表。

 

另,文章中用到了比较多的函数式编程的概念,虽然java原生不支持,但是函数式编程作为一种思想,肯定可以在命令式的程序设计中有所体现。

 

来源:http://www.iteye.com/topic/539515

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值