java 匿名类小结

从javaEye上转过来的文章,看完对一些以前的代码理解的更透彻了。转到自己博客上保存下。嘿。。

 

引言

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. });  

 通常使用匿名类的场景是,临时的创建一个类,实现指定的接口 ,使得调用者可以通过接口的方法来实现一定的操作。比如上边这个例子中,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);  

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

实例

在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. });  

 将一个匿名函数传递给另一个函数,实现一些列定制的动作,正好工作中有个地方要用到类似的东东,就用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. });  

 这样可以将很多的条件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 [email protected]  
  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. }  

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

Java代码
  1. package  org.free.fplist;  
  2.   
  3. /**  
  4.  * This is the interface defined Function-programmable support  
  5.  *   
  6.  * @author [email protected]  
  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. }  

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

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

好了,我们现在来看一个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. }  

使用匿名类

匿名类的使用是比较方便的,为了代码更简洁,我使用了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. }  

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原生不支持,但是函数式编程作为一种思想,肯定可以在命令式的程序设计中有所体现。

你可能感兴趣的:(java,object,String,filter,Integer,action)