zoukankan      html  css  js  c++  java
  • java的LINQ :Linq4j简明介绍

        开发JAVA一段时间,面临的一大问题就是集合操作,习惯了LINQ的简洁语法,对JAVA的集合操作实在是无甚好感,只能通过C系的循环实现筛选等操作,由于没有延迟执行特性,内存占用实在不敢恭维。因此便在网上找到了linq4j, 一个针对JAVA的linq移植版本。下面的文章,就会对这一工具进行简要的介绍。

    一. 安装

         该项目的Github地址是:https://github.com/julianhyde/linq4j. 显然是一个个人项目,向作者致敬。

         它并没有部署在标准的maven库里,因此需要手动编译生成。使用标准命令行:

     git clone git://github.com/julianhyde/linq4j.git linq4j    #git克隆到linq4j目录下
    
         mvn compile  #编译
    
         mvn test #测试
    
         mvn jar:jar  #生成jar包

         使用了maven以后,工作效率大大提升,.当然NET下也有类似的工具nuget.

    二. Linq4j的扩展功能

         由于JAVA目前还没有匿名函数和扩展函数,而且内置的标准迭代器接口Iterator功能偏弱。 因此Linq4j增加了一个一系列泛型接口和函数:

         1.  新迭代器接口: Enumerable<T>,它扩展了Iterator的功能

         2.  一组类似“委托”性质的函数: 

            (1)返回R的泛型委托:public interface Function<R> {}

            (2)接收T, 返回R的泛型委托:public interface Function1<T,R> {}

             (3)  接收T1,T2, 返回R的泛型委托,定义如下:

    /** 
     * Function with two parameters. 
     * 
     * @param <R> result type 
     * @param <T1> type of parameter 1 
     * @param <T2> type of parameter 2 
     */ 
    public interface Function2<T1, T2, R> extends Function<R> { 
      R apply(T1 v1, T2 v2); 
    }

       当然,内置的函数不止这些,还有一系列非泛型的委托,包括返回bool型的Predicate函数。由于篇幅限制,此处不一一介绍。

       3. 一系列Expressions,具体使用下面有介绍。

        三. 使用方法

         该库实现了大部分LINQ的功能,其中包括了筛选器,排序器,分组器,类型转换等功能。下面我们以一个实例来介绍它。

          先定义一个实体:

     public class Person
        {
        public int Age;
        public String     Name;
        public boolean Sex;
        }

          我们的基本任务,是将一个Person集合中,所有性别为男(true)的名字取出来,并按照string的默认降序排列。最后得到的应该是List<String>类型。

    //Linq4j:
    public
    void Test(ArrayList<Person> persList) { java.util.List<String> nameStrings= Linq4j.asEnumerable(persList).where(new Predicate1<Linq4jTest.Person>() { public boolean apply(Person arg0) { return arg0.Sex; } }).select(new Function1<Linq4jTest.Person, String>() { public String apply(Person arg0) { return arg0.Name; } }).orderByDescending(new Function1<String, String>() { public String apply(String arg0) { // TODO Auto-generated method stub return arg0; } }).toList(); }

          这段代码的风格和C#的很像,由于接口Enumerable可以拼接,因此通过简单的Where,Select和orderByDescending即可实现。但由于LINQ没有匿名函数,不得不在函数中加入函数,看起来实在是让人头疼。另外,由于没有扩展函数,需要在方法前使用Linq4j的静态方法。

         该功能利用标准Linq实现如下:

     var userNames = from d in persons where d.Sex orderby d.Name descending select d.Name;

         在.NET中,我们可以使用闭包,例如在筛选函数的实现中,访问到外部的数据。但我们可以看如下的例子:

         该函数的基本逻辑是找到personList中名字在黑名单里的人。套了两个Linq4j, 但是,注意blacklist数组的final关键字, 如果没有该关键字会报错,JAVA没有闭包,因此blacklist数组就不应该修改,这个语法糖到底是不是利大于弊,还需要读者讨论。

       public List<Person> SelectBlackList(ArrayList<Person> persList)
        {
        final String[] blackList = { "zhang", "wang", "li" };
        return Linq4j.asEnumerable(persList)
            .where(new Predicate1<Linq4jTest.Person>()
            {
    
                public boolean apply(Person arg0)
                {
                return Linq4j.asEnumerable(blackList).contains(
                    arg0.Name);
                }
    
            }).toList();
    
        }

         该功能使用标准Linq实现如下:

     public  List<Person> GetBlacklist(IEnumerable<Person> persons)
             {
                 String[] blackList = { "zhang", "wang", "li" };
                 var result= from d in persons where blackList.Contains(d.Name) select d;
                 return result.ToList();
             }

         最后讨论一下集合类型转换,例如类Worker继承实现了Person接口.

       public class Worker : Person
        {
            public string Commpay ;
    }

         那么,一个函数的定义是  void Func(List<Person> nodes). 而我要传入的参数类型是List<Worker>,编译器肯定是要报错的!怎么办?

         对于.NET来说,有逆变和协变特性,或者我可以这么做:

    public  void Test3(List<Worker>workers )
            {
                this.Func1(workers); //编译器会报错
                this.Func1(workers.OfType<Person>());
            }
            public void Func1(IEnumerable<Person>persons )
            {
                //只是演示,没有实现功能
          }

        对于JAVA来说,一般的做法,是在外面加一个转换,通过新建Person集合和foreach迭代器,利用强制类型转换将其转变为List<Person>. 这实在是太麻烦了。 利用LiNQ4J, 我们也有类似的语法:

      public void Func2(List<Person> person)
        {
        //演示,不实现功能
        }
        public void Test3(List<Worker> workers)//1.通过最简单粗暴的循环写法,实现功能,不敢恭维。
        {
        // Func2(workers); // 此处编译器会报错
        List<Person> persons = new ArrayList<Linq4jTest.Person>();
        for (Person person : workers)
        {
            persons.add(person);  
        }
                        Func2(persons);
        }
        public void Test4linq(List<Worker> workers)  //2.linq4j写法
        {
        List<Person> persons = Linq4j.asEnumerable(workers)
            .ofType(Person.class).toList(); 
        Func2(persons);
        }

        linq4j除了提供了这种显式声明函数的写法,还实现了以下的表达式写法,看起来真是高端洋气上档次:

     // use lambda, this time call whereN
        ParameterExpression parameterE =
            Expressions.parameter(Employee.class);
        ParameterExpression parameterN =
            Expressions.parameter(Integer.TYPE);
        final Queryable<Employee> nh3 =
            Linq4j.asEnumerable(emps)
                .asQueryable()
                .whereN(
                    Expressions.lambda(
                        Predicate2.class,
                        Expressions.andAlso(
                            Expressions.equal(
                                Expressions.field(
                                    parameterE,
                                    Employee.class,
                                    "deptno"),
                                Expressions.constant(10)),
                            Expressions.lessThan(
                                parameterN,
                                Expressions.constant(3))),
                        parameterE,
                        parameterN));

         看起来很唬人,但想起来其实不难。该功能利用Expressions类的静态方法,提供了一系列现成的函数供调用,一定程度上进一步提升了可用性。具体细节可以参照linq4j的源码,此处不打算深入讨论。

          四. 总结

            Linq4j实现了标准Linq的绝大多数功能,同时利用Expression类简化了很多简单函数的实现。使用起来还是很方便的,但我没有时间做具体的性能测试,因此在性能上没有发言权。但不论如何,膜拜一下作者的技术水平。如果大家有空,可以看看linq4j的源码,一定会有很多收获。

            集合操作是应用开发中最普遍的开发情形,可惜JAVA本身在该处并无太大建树,linq4j能不能用在大型项目上很难说,如果能在语言本身享受这种便利,那是最好不过的了,.NET系同学应该感到幸福。我们只能期待JAVA8带来的lamda表达式新特性,能更好的解决这个问题,当然这只能在2014年了。

            为了方便那些不用maven的同学,附件加上linq4j的jar包下载。 注意下载后改后缀名为jar.

        

          

  • 相关阅读:
    MVC ORM 架构
    Kubernetes 第八章 Pod 控制器
    Kubernetes 第七章 Configure Liveness and Readiness Probes
    Kubernetes 第六章 pod 资源对象
    Kubernetes 第五章 YAML
    Kubernetes 核心组件
    Kubernetes 架构原理
    Kubernetes 第四章 kubectl
    Kubernetes 第三章 kubeadm
    yum 配置及yum 源配置
  • 原文地址:https://www.cnblogs.com/buptzym/p/3282020.html
Copyright © 2011-2022 走看看