• jdk8新特性之lambda expressions


    本文分两部分:

    1. 语法简单说明
    2. lambda的使用

    注:这两部分内容均以类+注释的方式进行说明,并且内容均来自官方教程(https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)。

    第一部分:

    /**
    * 语法说明类
    *
    * lambda表达式包含下面几个要素:
    * 1、逗号分隔的参数列表,如CheckPerson。test(Person p),其中p表示一个Person的对象实例
    * 2、向右箭头 →, 箭头左侧是表达式入参,箭头右侧是表达式本身
    * 3、表达式体,包含单个表达式或者一个语句块
    *
    * @author zhuotao
    *
    */
    public class SyntaxInstruction {

      public static void main(String[] args) {


    List<Person> persons = PersonGenerator.generatePerons();
      printPerson(persons, p -> p.getAge() > 30 && p.getAge() < 50);
    }

    public static void printPerson(List<Person> persons, CheckPerson cp) {
      for(Person p : persons) {
        if(cp.test(p)) System.out.println(p);
      }
    }
    }

    interface CheckPerson{
      public boolean test(Person p);
    }

    第二部分:

    假设一种场景:
    A正在开发一个社交网络应用,考虑添加一个功能——管理员可以根据用户(Person)的不同特征,执行不同的操作,比如发送信息。

    approaches是A写的不同的实现,从a1 ~ a8,看看每个方法较之前有什么明显的提升。

    备注:1> Person 社交网络应用用户类  2> PersonGenerator 用户列表模拟产生类

    方法一:

    /**
    * 方法一:创建一个方法,用于查询某个特征的用户
    * 1、方法入参:
    * persons 用户列表
    * age 约束条件,最低年龄
    * 2、输出打印满足条件的用户信息
    *
    * 不过,总感觉有什么不对,如果有一天功能的约束条件增加该怎么办?比如,“同事满足age<50”的条件
    * 所以,写了第二个方法,见a2.Approch2
    *
    * @author zhuotao
    *
    */
    public class Approch1 {

      public static void main(String[] args) {
        List<Person> persons = PersonGenerator.generatePerons();
        printPersonOlderThan(persons, 30);
      }

      public static void printPersonOlderThan(List<Person> persons, int age) {
         for(Person p : persons) {
          if(p.getAge() > age) {
            p.printPerson();
          }
         }
      }

    }

    方法二:

    /**
    * 方法二:增强方法的限定规则,判断年龄时,用区间进行判断
    * 额,这跟第一种方法就是换汤不换药嘛,没什么改进哈~Σ( ° △ °|||)︴
    *
    * 于是,第三种方案应运而生。见 a3/Approach3
    *
    * @author zhuotao
    *
    */
    public class Approach2 {

    public static void main(String[] args) {
      List<Person> persons = PersonGenerator.generatePerons();
      printPersonOlderThan(persons, 30, 50);
    }

    public static void printPersonOlderThan(List<Person> persons, int low, int high) {
      for(Person p : persons) {
        if(p.getAge() > low && p.getAge() < high) {
          p.printPerson();
        }
      }
    }


    }

    方法三:

    /**
    * 方法三:创建规则判断接口
    * 将规则判断独立出业务判断,如果新增规则约束,那么只需要实现CheckPerson,重写test即可
    *
    * 仔细想,要是规则很多,肿么办?肿么办?
    * 先后有100种规则,是不是要创建100种实现?那类的数量。。。~~~~(>_<)~~~~ 此路不通~
    *
    * 于是,试试第四中方法,见 a4/Approach4
    *
    * @author zhuotao
    *
    */
    public class Approach3 {

    public static void main(String[] args) {

      List<Person> persons = PersonGenerator.generatePerons();
      printPerson(persons, new SearchPersonsByAage());

    }

    public static void printPerson(List<Person> persons, CheckPerson check) {
      for(Person p : persons) {
        if(check.test(p)) p.printPerson();
      }
    }

    }

    class SearchPersonsByAage implements CheckPerson {

    @Override
    public boolean test(Person p) {
      return p.getAge() > 30 && p.getAge() < 50;
    }

    }

    interface CheckPerson {
      public boolean test(Person p);
    }

    方法四:

    /**
    * 方法四:使用匿名内部类
    * 使用这种方法,再也不用担心规则类的膨胀问题了~哇咔咔~
    *
    * 可是,这真的就是想要的方案么?蛋然不是啦~~
    *
    * 来吧,进入今天的主题——lambda expressions, 见a5/Approach5
    *
    * @author zhuotao
    *
    */
    public class Approach4 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        printPerson(persons, new CheckPerson() {
          @Override
          public boolean test(Person p) {
            return p.getAge() > 30 && p.getAge() < 50;
          }
        });

      }

      public static void printPerson(List<Person> persons, CheckPerson check) {
        for(Person p : persons) {
          if(check.test(p)) p.printPerson();
        }
      }

    }

    interface CheckPerson {
      public boolean test(Person p);
    }

    方法五:

    /**
    * 方法五,使用lambda表达式
    * lambda表达式,需要依赖一个功能接口。这里的功能接口,是指只包含一个抽象方法的接口。如,下面的CheckPerson
    *
    * 这个例子,发生了什么,连匿名内部类都不需要了,(~ o ~)~zZ 也太简洁了吧~
    * 同样是规则判断,这里只需要一个功能接口,一个表达式就解决了规则判断的问题。 (*^__^*)
    *
    * 这就满足了? 还没有结束哦,卡木昂,北鼻 ,随我来,见 a6/Approach6
    *
    * @author zhuotao
    *
    */
    public class Approach5 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        printPerson(persons, (Person p) -> p.getAge() > 30 && p.getAge() < 50);
        // 等价于
        //printPerson(persons, p -> p.getAge() > 30 && p.getAge() < 50);

      }

      public static void printPerson(List<Person> persons, CheckPerson check) {
        for(Person p : persons) {
          if(check.test(p)) p.printPerson();
        }
      }

    }

    interface CheckPerson {
      public boolean test(Person p);
    }

    方法六:

    /**
    * 方法六:使用通用功能接口+lambda表达式
    * 知道方法5的问题在哪里么? 我来告诉你哈~~
    * 因~为~那~个~功~能~接~口~不~通~用~,如果我判断Person之外的对象,岂不是~
    *
    * 是的,将功能进行通用化处理,参考 Predicate<T> T通用的泛型
    *
    * 该逻辑: printAdmin(amdins, admin -> "xxxxxx".equals(admin.getPrivilegeCode()));
    *
    * 在这里lambda的优势已经基本上明了——
    * 使用功能接口,替换内部类的使用,降低类膨胀风险;
    * 表达式语法简单,简洁易懂;
    * 减少coding
    *
    * 以上,只是自己的片面之言,总结未必到位欢迎补充。
    *
    * 看到这,lambda已经基本结束了,不过,如果继续看下面的优化相信你会有更大的收获,见 a7/Approach7
    *
    * @author zhuotao
    *
    */
    public class Approach6 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        printPerson(persons, (Person p) -> p.getAge() > 30 && p.getAge() < 50);
        // 等价于
        //printPerson(persons, p -> p.getAge() > 30 && p.getAge() < 50);

        // 下面只是一个示例,用于说明通用功能接口的优势
        // List<Aministrator> amdins = new ArrayList<Aministrator>();
        // printAdmin(amdins, admin -> "xxxxxx".equals(admin.getPrivilegeCode()));

      }

      public static void printPerson(List<Person> persons, Predicate<Person> check) {
        for(Person p : persons) {
          if(check.test(p)) p.printPerson();
        }
      }

      public static void printAdmin(List<Aministrator> admins, Predicate<Aministrator> check) {
        for(Aministrator admin : admins) {
          if(check.test(admin)) admin.printAdmin();
        }
      }


    }

    class Aministrator {


    private String name;
    private String id;
    private String privilegeCode;
    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
    public String getId() {
      eturn id;
    }
    public void setId(String id) {
      this.id = id;
    }
    public String getPrivilegeCode() {
      return privilegeCode;
    }
    public void setPrivilegeCode(String privilegeCode) {
      this.privilegeCode = privilegeCode;
    }

    @Override
    public String toString() {
      return "Aministrator [name=" + name + ", id=" + id + ", privilegeCode="
        + privilegeCode + "]";
    }

    public void printAdmin() {
      System.out.println(toString());
    }

    }

    interface Predicate<T> {
      public boolean test(T t);
    }

    方法七:

    /**
    * 方法七:怎么将lambda表达式贯穿到整个应用呢?
    * 我稀饭这个标题,因为,这表达的是一种技巧,一种思路
    *
    * 试想,printPerson方法做了什么?1、接收用户列表 2、规则判断 3、输出打印符合条件的用户信息
    * 那如果我有相似的逻辑:比如 1、接收用户列表(待处理数据) 2、执行某个规则(lambda表达式) 3、发送用户信息(操作) 该如何操作呢?
    * 这里还是以List<Person> 作为待处理数据,进行优化
    * 看processPersons(persons, p -> p.getAge() > 30 && p.getAge() < 50, p -> p.printPerson()); 这个逻辑,你会发现;
    * 相同的数据,将规则和规则之后的操作进行了分离。
    *
    * 那啥,是不是很带感,那就继续,见 a8/Approach8
    *
    * 注意: 这里使用了 java.util.function.Consumer, 没看错,在jdk8中新引入的function包
    *
    * 不妨看看Consumer的注释信息(除了accept方法,还有个默认方法,感兴趣的同学可以研究下~)
    *
    * **
    * Represents an operation that accepts a single input argument and returns no
    * result. Unlike most other functional interfaces, {@code Consumer} is expected
    * to operate via side-effects.
    *
    * <p>This is a <a href="package-summary.html">functional interface</a>
    * whose functional method is {@link #accept(Object)}.
    *
    * @param <T> the type of the input to the operation
    *
    * @since 1.8
    *
    * @FunctionalInterface //这里使用了功能接口的标注
    public interface Consumer<T> {......}
    *
    *
    * @author zhuotao
    *
    */
    public class Approach7 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        processPersons(persons, p -> p.getAge() > 30 && p.getAge() < 50, p -> p.printPerson());

      }

      public static void processPersons(List<Person> persons, Predicate<Person> check, Consumer<Person> block) {
        for(Person p : persons) {
          if(check.test(p)) block.accept(p);;
        }
      }

    }

    interface Predicate<T> {
      public boolean test(T t);
    }

    方法八:

    /**
    * 方法八:依然是将lambda表达式运用到整个应用
    * 整个题目的调调跟方法七很像,其实a8和a7的关系就像是a6和a5的关系,只是用来说明通用性的
    *
    * 看到下面的逻辑,有什么想说的? 我是想说,简直太神奇了~~喵喵的~~神奇的jdk8~哇咔咔~
    *
    * 不过,在新事物(Consumer 和 Function)面前是不是感觉有点不适应,那么接下来就再次见证奇迹吧~
    * 见~~~~a9/Approach9
    *
    * 值得注意的是,这里同样使用了jdk8新增的一个类:java.util.function.Function
    * 该类注释如下:
    * **
    * Represents a function that accepts one argument and produces a result.
    *
    * <p>This is a <a href="package-summary.html">functional interface</a>
    * whose functional method is {@link #apply(Object)}.
    *
    * @param <T> the type of the input to the function
    * @param <R> the type of the result of the function
    *
    * @since 1.8
    *
    * @author zhuotao
    *
    */
    public class Approach8 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        processElements(
              persons,
              p -> p.getAge() > 30 && p.getAge() < 50,
              p -> p.getName(),
              name -> System.out.println(name));

      }

    /**
    * 通用的处理逻辑
    * @param source 源数据
    * @param tester 通用规则校验函数接口
    * @param mapper Funtion mapper,具体请参见function源码,接收一个参数,并返回结果
    * @param block
    */
    public static <X, Y> void processElements(
        Iterable<X> source,
        Predicate<X> tester,
        Function <X, Y> mapper,
        Consumer<Y> block) {

      for (X p : source) {
        if (tester.test(p)) {
        Y data = mapper.apply(p);
        block.accept(data);
      }
    }

    }

    }


    interface Predicate<T> {
      public boolean test(T t);
    }

    方法九:

    /**
    * 方法九:Stream操作,也就是聚集操作(aggregate operations)
    *
    * 先看下面的例子,小伙伴惊呆了么? 神奇的jdk8~
    *
    * 简单来说,下面的处理通过对集合进行了stream处理; stream 就是集合元素的序列,和Collection不同,stream不是用来存储数据的数据结构,它是通过管道(pipeline)从数据源获取数据。
    * pipeline是stream操作的序列,比如本例子中的 filter-map-foreach。 换言之,数据仍然是保存在集合中,聚集操作需要数据时实时获取
    *
    * 题外话:collection 除了扩展stream之外,还新增了spliterator parallelStream两个方法,感兴趣的同学,巴拉巴拉源码或者debug下本示例进行了解吧~
    *
    * 到这里lambda表达式入门总算结束了,希望这个专题让大家认识了jdk8的新成员——lambda表达式
    * (~ o ~)~zZ 好书湖啦~
    *
    *
    * @author zhuotao
    *
    */
    public class Approach9 {

      public static void main(String[] args) {

        List<Person> persons = PersonGenerator.generatePerons();
        persons
          .stream() // * Returns a sequential {@code Stream} with this collection as its source.
          .filter(p -> p.getAge() > 30 && p.getAge() < 50) //Returns a stream consisting of the elements of this stream that match the given predicate.
          .map(p -> p.getName()) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
          .forEach(name -> System.out.println(name)); // Performs an action for each element of this stream.

      }

    }

    interface Predicate<T> {
      public boolean test(T t);
    }

  • 相关阅读:
    Mybatis入门
    Spring的xml文件配置方式实现AOP
    jquery简直是太酷炫强大了
    [Google Guava] 2.2-新集合类型
    小规模的流处理框架.Part 1: thread pools
    数据库三大范式和五大约束
    Hibernate:缓存
    MyBatis:缓存配置
    Python:协程
    微信公众号开发之测试账号
  • 原文地址:https://www.cnblogs.com/aking1988/p/4544487.html
Copyright © 2020-2023  润新知