Lambda是什么?

Lambda是一个匿名函数,我们可以把Lambda理解为是一段可以传递的代码。可以写出简洁、灵活的代码。作为一种更紧凑的代码风格,使java的语言表达能力得到提升。

可以这么说lambda表达式其实就是实现SAM接口(函数式编程)的语法糖。lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名类。

Lambda表达式语法

Lambda表达式在java语言中引入了一个新的语法元素和操作符。这个操作符为"->",该操作符被称为Lambda操作符或箭头操作符,它讲Lambda分为两个部分
左侧:指定了Lambda表达式所需要的所有参数
右侧:指定了Lambda体,即Lambda表达式所要执行的功能。

语法格式一:无参,无返回值,Lambda体只需要一条语句。

Runnable r1 = () -> System.out.println("Hello Lambda!");

语法格式二:Lambda需要一个参数

Consumer<String> con = (x) -> System.out.println(x);

语法格式三:Lambda只需要一个参数时,参数的小括号可以省略

Consumer<String> con = x -> System.out.println(x);

语法格式四:Lambda需要两个参数,并且有返回值

Comparator<Integer> com = (x, y) -> {
  System.out.println("函数式接口");   return Integer.compare(x, y); };

语法格式五:当Lambda体只有一条语句时,return与大括号可以省略

Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

语法格式六:数据类型可以省略,因为可由编译器推断得出,称为类型推断

BinaryOperator<Long> operator = (Long x, Long y) -> {
System.out.println("实现函数接口方法"); return x + y; };

函数式接口

只包含一个抽象方法的接口,称为函数式接口。可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。

自定义函数式接口

@FunctionalInterface

  public interface MyNumber {

  public double getValue();

}

函数式接口中使用泛型

@FunctionalInterface

    public interface MyFunc<T> {

    public T getValue(T t);

}

作为参数传递Lambda表达式

public String toUpperString(MyFunc<String> mf, String str) {

    return mf.getValue(str);

}

String str = toUpperString((x) -> x.toUpperCase(), "abcdef");

System.out.println(str);

作为参数传递Lambda表达式:为了将Lambda表达式作为参数传递,接收Lambda表达式的参数类型必须是与该Lambda表达式兼容的函数式接口类型。

java内置四大核心函数式接口

四大核心接口

①消费型接口

//Consumer<T> 消费型接口 :

@Test

public void test1(){

    happy(10000, (m) -> System.out.println(m));

}

public void happy(double money, Consumer<Double> con){

    con.accept(money);

}

②供给型接口

//Supplier<T> 供给型接口 :

@Test

public void test2(){

  List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));

  for (Integer num : numList) {

    System.out.println(num);

  }

}
//需求:产生指定个数的整数,并放入集合中 public List<Integer> getNumList(int num, Supplier<Integer> sup){   List<Integer> list = new ArrayList<>();   for (int i = 0; i < num; i++) {     Integer n = sup.get();     list.add(n);   }   return list; }

③函数型接口

//Function<T, R> 函数型接口:

@Test

public void test3(){

  String newStr = strHandler("\t\t\t 好好学习天天向上 ", (str) -> str.trim());

  System.out.println(newStr);

  String subStr = strHandler("好好学习天天向上", (str) -> str.substring(2, 5));

  System.out.println(subStr);

}

//需求:用于处理字符串

public String strHandler(String str, Function<String, String> fun){

  return fun.apply(str);

}

④断言型接口

//需求:将满足条件的字符串,放入集合中

public List<String> filterStr(List<String> list, Predicate<String> pre){

  List<String> strList = new ArrayList<>();

  for (String str : list) {

    if(pre.test(str)){

      strList.add(str);

    }

  }

  return strList;

}

//Predicate<T> 断言型接口:

@Test

public void test4(){

  List<String> list = Arrays.asList("Hello", "atntjr", "Lambda", "www", "ok");

  List<String> strList = filterStr(list, (s) -> s.length() > 3);

  for (String str : strList) {

    System.out.println(str);

  }

}

其他接口

方法引用于构造器引用

方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法参数列表保持一致)
方法引用:使用操作符"::"将方法名和对象或者类的名字分隔开来。如下三种主要使用情况:
对象::实例方法
类::静态方法
类::实例方法
注意:
①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName。

构造器引用

构造器的参数列表,需要与函数式接口中参数列表保持一致!
类名::new

数组引用

类型[]::new

例子

①对象的引用::实例方法名

@Test

public void test2(){

  Employee emp = new Employee(101, "张三", 18, 9999.99);

  Supplier<String> sup = () -> emp.getName();
  System.out.println(sup.get());   System.out.println("----------------------------------");   Supplier<String> sup2 = emp::getName;   System.out.println(sup2.get()); }

②类名::静态方法名

@Test

public void test4(){

    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

    System.out.println("-------------------------------------");

    Comparator<Integer> com2 = Integer::compare;

}

③类名::实例方法名

@Test

public void test5(){

  BiPredicate<String, String> bp = (x, y) -> x.equals(y);

  System.out.println(bp.test("abcde", "abcde"));

  System.out.println("-----------------------------------------");

  BiPredicate<String, String> bp2 = String::equals;

  System.out.println(bp2.test("abc", "abc"));

  System.out.println("-----------------------------------------");

  Function<Employee, String> fun = (e) -> e.show();

  System.out.println(fun.apply(new Employee()));

  System.out.println("-----------------------------------------");

  Function<Employee, String> fun2 = Employee::show;

  System.out.println(fun2.apply(new Employee()));

}

④构造器引用

@Test

public void test7(){

  Function<String, Employee> fun = Employee::new;

  BiFunction<String, Integer, Employee> fun2 = Employee::new;

}

⑤数组引用

@Test

public void test8(){

  Function<Integer, String[]> fun = (args) -> new String[args];

  String[] strs = fun.apply(10);

  System.out.println(strs.length);

  System.out.println("--------------------------");

  Function<Integer, Employee[]> fun2 = Employee[] :: new;

  Employee[] emps = fun2.apply(20);

  System.out.println(emps.length);

}

lambda表达式可使用的变量

先举例:

//将为列表中的字符串添加前缀字符串
String waibu = "lambda :";
List<String> proStrs = Arrays.asList(new String[]{"Ni","Hao","Lambda"});
List<String>execStrs = proStrs.stream().map(chuandi -> {
Long zidingyi = System.currentTimeMillis();
return waibu + chuandi + " -----:" + zidingyi;
}).collect(Collectors.toList());
execStrs.forEach(System.out::println);

输出:

lambda :Ni -----:1474622341604
lambda :Hao -----:1474622341604
lambda :Lambda -----:1474622341604

变量waibu :外部变量

变量chuandi :传递变量

变量zidingyi :内部自定义变量

lambda表达式可以访问给它传递的变量,访问自己内部定义的变量,同时也能访问它外部的变量。

不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。

当在表达式内部修改waibu = waibu + " ";时,IDE就会提示你:

Local variable waibu defined in an enclosing scope must be final or effectively final

编译时会报错。因为变量waibu被lambda表达式引用,所以编译器会隐式的把其当成final来处理。

以前Java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。现在java8对这个限制做了优化,可以不用显示使用final修饰,但是编译器隐式当成final来处理。

lambda表达式中的this概念

在lambda中,this不是指向lambda表达式产生的那个SAM对象,而是声明它的外部对象。

例如:

也就是说在这个例子里,this指的是WhatThis ,而不是execStrs

public class WhatThis {

     public void whatThis(){
//转全小写
List<String> proStrs = Arrays.asList(new String[]{"Ni","Hao","Lambda"});
List<String> execStrs = proStrs.stream().map(str -> {
System.out.println(this.getClass().getName());
return str.toLowerCase();
}).collect(Collectors.toList());
execStrs.forEach(System.out::println);
} public static void main(String[] args) {
WhatThis wt = new WhatThis();
wt.whatThis();
}
}

输出:

com.wzg.test.WhatThis
com.wzg.test.WhatThis
com.wzg.test.WhatThis
ni
hao
lambda

方法引用和构造器引用

本人认为是进一步简化lambda表达式的声明的一种语法糖。

前面的例子中已有使用到: execStrs.forEach(System.out::println);

方法引用

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()。

可以这么理解,前两种是将传入对象当参数执行方法,后一种是调用传入对象的方法。

构造器引用

构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x->new BigDecimal(x)。

Java 8 Lambda表达式介绍的更多相关文章

  1. JAVA 8 Lambda表达式-Lambda Expressions

    Lambda表达式介绍 Lambda表达式是在java规范提案JSR 335中定义的,Java 8 中引入了Lambda表达式,并被认为是Java 8最大的新特性,Lambda表达式促进了函数式编程, ...

  2. Java 8 Lambda表达式

    Java 8 Lambda表达式探险 http://www.cnblogs.com/feichexia/archive/2012/11/15/Java8_LambdaExpression.html 为 ...

  3. 深入浅出 Java 8 Lambda 表达式

    摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等.本文系 OneAPM 工程师编译整理. Java 是一流的面向对象语言,除了部分简 ...

  4. Java 8 Lambda表达式10个示例【存】

    PS:不能完全参考文章的代码,请参考这个文件http://files.cnblogs.com/files/AIThink/Test01.zip 在Java 8之前,如果想将行为传入函数,仅有的选择就是 ...

  5. Java 8 Lambda 表达式

    Lambda 是啥玩意 简单来说,Lambda 就是一个匿名的方法,就这样,没啥特别的.它采用一种非常简洁的方式来定义方法.当你想传递可复用的方法片段时,匿名方法非常有用.例如,将一个方法传递给另外一 ...

  6. Java 8 lambda表达式示例

    例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...

  7. Java基础学习总结(44)——10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...

  8. 02、Java的lambda表达式和JavaScript的箭头函数

    前言 在JDK8和ES6的语言发展中,在Java的lambda表达式和JavaScript的箭头函数这两者有着千丝万缕的联系:本次试图通过这篇文章弄懂上面的两个"语法糖". 简介 ...

  9. 转载:深入浅出 Java 8 Lambda 表达式

    原文地址:http://viralpatel.net/blogs/Lambda-expressions-java-tutorial/ OneAPM for Java 能够深入到所有 Java 应用内部 ...

随机推荐

  1. Jenkins使用SSH远程发布

    远程发布需要安装Publish Over SSH插件 比如我们的应用服务器都是通过tomcat用户启动程序,因此,在jenkin服务器上配置免密登录远程服务器tomcat用户 //生成密钥对 ssh- ...

  2. Hnoi2013题解 bzoj3139~3144

    话说好久没写题(解)了.. 先贴份题解:http://wjmzbmr.com/archives/hnoi-2013-%E9%A2%98%E8%A7%A3/(LJ神题解..Lazycal表示看不懂..) ...

  3. [BZOJ 4033] 树上染色

    Link: BZOJ 4033 传送门 Solution: 此题用到了计算贡献的方法, 将 多条路径的路径和  $->$ $\sum_{i=1}^{n-1} w[i]*cnt[i]$ 这样我们由 ...

  4. [xsy2363]树

    设$f_{i,j}$表示$i$个点的树,权值为$j$且可以不选根的方案数,$g_{i,j}$表示$i$个点的树,权值为$j$且必选根的方案数 首先$g_{1,1}=0$ 我们可以把原树连上一个新的子树 ...

  5. 找出分数最高的前两个学生 Exercise05_09

    import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:找出分数最高的前两个学生 * */ public class Exerci ...

  6. Entity Framework part1

    First Demo实体框架Entity Framework,简称EFEF是微软推出的基于Ado.Net的数据库访问技术,是一套ORM框架底层访问数据库的实质依然是ado.net是一套orm框架,即框 ...

  7. Mac Screen Capture Shortcuts

    Here's How:   To capture the entire desktop, press Command-Shift-3. The screen shot will be automati ...

  8. oracle 对应的JDBC驱动 版本

    Oracle版本 jdk版本 推荐jar包 备注 Oracle 8i JDK 1.1.x classes111.zip   Oracle 8i JDK 1.1.x classes12.zip   Or ...

  9. oracle 11g jdbc jar包在哪个文件目录

    一. 如果装了oracle数据库的话, 大致是这样的目录:    D:\oracle\product\11.2.0\client_1\oui\jlib\classes12.jar 或者    D:\o ...

  10. fastjson用法&Gson

    <dependency>    <groupId>com.google.code.gson</groupId>   <artifactId>gson&l ...