• Java1.8新特性之Lambda


    经常在代码中用到Lambda ,结合个人经验及网络学习做一个总结性的文章,方便后续使用。

    List<String> names = ...;
    Collections.sort(names, (o1, o2) -> o1.compareTo(o2));
    List<String> lowercaseNames = names.stream().map(name -> name.toLowerCase();).collect(Collectors.toList());

     Arrays.stream(names).forEach(System.out::println);//转成流
     Arrays.asList(names).forEach(System.out::println);//转成list

    (int a, int b) -> {  return a + b; }
    () -> System.out.println("Hello World");
    (String s) -> { System.out.println(s); }
    () -> 42
    () -> { return 3.1415 };

    Java8之Lambda相关常用方法使用

    • stream()  将集合转为流

    • collect()  将流转成集合

    • filter()      将转为流的集合过滤出满足要求的流

    • map()      将每个元素映射成新元素

    • limit()      获取n个元素

    • skip()      跳过n元素

    • skip和limit组合实现分页(对数据库的压力没有减轻,只是看着分页了)

    • distinct   去除重复元素

          //五个user对象
            User user1 = new User(1, "张三", 10);
                ......
            User user5 = new User(5, "严七", 30);
     
            //将User对象存入list
            List<User> userList = new ArrayList<>();
                ......
            userList.add(user5);
     
            //1.stram()方法:将集合装为流
            Stream<User> stream = userList.stream(); 参考文章深入理解Stream
            System.out.println(stream);//打印对象地址。java.util.stream.ReferencePipeline$Head@65f651eb
     
            //2.collect()方法:将流转为集合
            List<User> users = userList.stream().collect(Collectors.toList());
            System.out.println(users);//[User{id=1, username='张三', age=10}.... User{id=5, username='严七', age=30}]
     
            //3.filter()方法:将转为流的集合过滤出满足要求的流
            List<User> userList1 = userList.stream().//将集合转为流
                    filter(user -> user.getAge() > 20).//过滤出年龄大于20的user。(类似于sql中的where user.age > 20)
                    collect(Collectors.toList());//将流转回集合(便于打印观察结果)
            System.out.println(userList1);//[User{id=4, username='赵六', age=25}, User{id=5, username='严七', age=30}]
     
            //4.map()方法:将每个元素映射成新元素
            List<User> userList2 = userList.stream().filter(user -> user.getAge() > 20).//过滤出年龄大于20的user
                    map(user -> {
                user.setAge(50);//执行你想要的操作,将过滤得到的user对象年龄设置为50
                return user;//每个元素都会映射产生新元素,所以map()方法要有返回值,返回新元素
            }).collect(Collectors.toList());//将流转为集合
             System.out.println(userList2);//[User{id=4, username='赵六', age=50}, User{id=5, username='严七', age=50}]
     
            //5.limit(n):获取n个元素,类似于MySQL数据库中 'limit 参数1,参数2' 关键字:参数2
            List<User> userList3 = userList.stream().limit(3).collect(Collectors.toList());//获取前三个元素。
            System.out.println(userList3);//[User{id=1, username='张三', age=10}.... User{id=3, username='王五', age=20}]
     
            //6.  skip(n):跳过n元素,类似于MySQL数据库中 'limit 参数1,参数2' 关键字:参数1
            List<User> userList4 = userList.stream().skip(2).collect(Collectors.toList());//跳过两个元素
            System.out.println(userList4);//[User{id=3, username='王五', age=20},..., User{id=5, username='严七', age=50}]
     
            //7.skip和limit组合实现分页
            List<User> userList5 = userList.stream().skip(2).limit(2).collect(Collectors.toList());//获取第二页数据(每页显示两条数据)
            System.out.println(userList5);//[User{id=3, username='王五', age=20}, User{id=4, username='赵六', age=50}]
     
            //8.  distinct:去除重复元素
            //向集合中插入一个重复元素
            userList.add(user5);
            System.out.println(userList);//..., User{id=5, username='严七', age=50}, User{id=5, username='严七', age=30}]
            List<User> userList6 = userList.stream().distinct().collect(Collectors.toList());//去重(实体类中需要实现equals()和hashCode())
            System.out.println(userList6);//[User{id=1, username='张三', age=10},..., User{id=5, username='严七', age=50}]                                    

    1.lambda表达式

      维基百科对Lambda 表达式的解释是:a function (or a subroutine) defined, and possibly called, without being bound to an identifier。简单翻译过来就是,一个不需要绑定标识符(即不需要声明)且可能被调用的定义方法(子程序)。

      语法: (argument) -> (body);

          详细语法:(Type1 param1,Type2  param2, ..., paramN) -> {

                 statment1;

                 statment2;

                .....

                 return  statmentM;

              }

      语法结构:

    1 Lambda 表达式可以具有零个,一个或多个参数。
    2 可以显式声明参数的类型,也可以由编译器自动从上下文推断参数的类型。例如 (int a) 与刚才相同 (a)。
    3 参数用小括号括起来,用逗号分隔。例如 (a, b) 或 (int a, int b) 或 (String a, int b, float c)。
    4 空括号用于表示一组空的参数。例如 () -> 425 当有且仅有一个参数时,如果不显式指明类型,则不必使用小括号。例如 a -> return a*a。
    6 Lambda 表达式的正文可以包含零条,一条或多条语句。
    7 如果 Lambda 表达式的正文只有一条语句,则大括号可不用写,且表达式的返回值类型要与匿名函数的返回类型相同。
    8 如果 Lambda 表达式的正文有一条以上的语句必须包含在大括号(代码块)中,且表达式的返回值类型要与匿名函数的返回类型相同。

    2.为什么要用Lambda表达式

      Java 是面向对象语言,除了原始数据类型之处,Java 中的所有内容都是一个对象。而在函数式语言中,我们只需要给函数分配变量,并将这个函数作为参数传递给其它函数就可实现特定的功能。JavaScript 就是功能编程语言的典范(闭包)。

      Lambda 表达式的加入,使得 Java 拥有了函数式编程的能力。在其它语言中,Lambda 表达式的类型是一个函数;但在 Java 中,Lambda 表达式被表示为对象,因此它们必须绑定到被称为功能接口的特定对象类型。

    3.Lambda的使用

      ①参数类型省略–绝大多数情况,编译器都可以从上下文环境中推断出lambda表达式的参数类型。这样lambda表达式就变成了:

    //不使用Lambda
    List<String> names = ...;//这里省略list的构造
    Collections.sort(names, new Comparator<String>() {
      @Override
      public int compare(String o1, String o2) {
        return o1.compareTo(o2);
      }
    });
    
    //使用Lambda
    List<String> names = ...;//这里省略list的构造
    Collections.sort(names, (o1, o2) -> o1.compareTo(o2));

    ②当lambda表达式的参数个数只有一个,可以省略小括号。lambda表达式简写为:

    List<String> names = ...;//这里省略list的构造
    List<String> lowercaseNames = names.stream().map((String name) -> {return name.toLowerCase();}).collect(Collectors.toList());
    
    //简化后
    List<String> lowercaseNames = names.stream().map(name -> {return name.toLowerCase();}).collect(Collectors.toList());

    ③当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号。lambda表达式简化为:

      param -> statement

    List<String> lowercaseNames = names.stream().map(name -> name.toLowerCase()).collect(Collectors.toList());

     ④数组使用lambda

      数组不能直接在foreach中使用

     a.forEach(System.out::println);//错误
    Arrays.stream(a).forEach(System.out::println);//转成流
    Arrays.stream(a).boxed().collect(Collectors.toList()).forEach(System.out::println);//int [] a,转成list
    Arrays.asList(a).forEach(System.out::println);//Integer [] a,转成list

    ⑤集合使用lambda

    arrayList.forEach(System.out::println);
    hashMap.forEach((k,v)->System.out.println(k+"_"+v.intValue()));

    ⑥JSONArray使用lambda

      例如,使用JsonArray:[{name:“John”},{name:“David”}]并返回[“John”,“David”]的列表的函数。

    写了下面的代码:

    import org.json.simple.JSONArray; 
    import org.json.simple.JSONObject; 
    
    public class Main { 
        public static void main(String[] args) { 
         JSONArray jsonArray = new JSONArray(); 
         jsonArray.add(new JSONObject().put("name", "John")); 
      
    System.out.println(new JSONObject().put("name", "John"));//输出null
         List list = (List) jsonArray.stream().map(json -> json.toString()).collect(Collectors.toList()); 
    System.out.println(list); //输出[null]
    }
    }
    错误:
    Exception in thread "main" java.lang.NullPointerException

    JSONArrayjava.util.ArrayList的子类和JSONObjectjava.util.HashMap的子类。

    因此,new JSONObject().put("name", "John")返回与密钥(null)关联的先前值,而不是JSONObject实例。结果,null被添加到JSONArray
    解决:
    JSONArray jsonArray = new JSONArray(); 
    JSONObject j1 = new JSONObject(); 
    j1.put ("name", "John"); 
    jsonArray.add(j1); 
    List list = (List) jsonArray.stream().map(json -> json.toString()).collect(Collectors.toList()); 
    System.out.println(list); //结果:[{"name":"John"}]

    4.方法引用

      双冒号操作符

        双冒号运算操作符是类方法的句柄,lambda 表达式的一种简写,这种简写的学名叫 eta-conversion 或者叫 η-conversion

    通常的情况下:

    把 x -> System.out.println(x) 简化为 System.out::println 的过程称之为 eta-conversion
    
    把 System.out::println 转化为 x -> System.out.println(x) 的过程称之为 eta-expansion

    双冒号运算就是 java 中的[方法引用]。 [方法引用]格式为:类名::方法名

    注意方法名,后面没有括号“()”的。为啥不要括号,因为这样的是式子并不代表一定会调用这个方法。这种式子一般是用作Lambda表达式,Lambda有所谓懒加载嘛,不要括号就是说,看情况调用方法。

    使用方法格式有三种

    • objectName::instanceMethod
    • ClassName::staticMethod
    • ClassName::instanceMethod

    前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。

    最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。比如String::toLowerCase等同于x->x.toLowerCase()。

    表达式:    person -> person.getAge();  可以替换成    Person::getAge
    表达式:    () -> new HashMap<>();  可以替换成    HashMap::new

    这种 [方法引用] 或者说 [双冒号运算] 对应的参数类型是 Function<T, R> T 表示传入类型,R 表示返回类型。

    比如表达式 person -> person.getAge(); 传入参数是 person,返回值是 person.getAge() ,那么方法引用Person::getAge 就对应着 Function<Person,Integer> 类型。

    collected.stream().map(string -> string.toUpperCase()).collect(Collectors.toList());
    可以修改为:
    collected.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));//

    5.构造器引用

    构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。

    例如BigDecimal::new等同于x->new BigDecimal(x)

    部分内容借鉴文章:https://segmentfault.com/a/1190000009186509

  • 相关阅读:
    学习asp.net完整步骤
    UltraEdit中Matlab语法高亮显示的操作方法
    C#基础完成和深入
    75道程序员面试逻辑思维题
    模拟退火算法解决函数优化问题
    模拟退火算法解决TSP问题
    C#入门
    简单感知器模型解决简单真值表问题
    jQuery 1.3.2 :visible选择器问题
    NUnit2.0详细使用方法
  • 原文地址:https://www.cnblogs.com/chen2608/p/14410850.html
Copyright © 2020-2023  润新知