1. Lambda 表达式概述

  • Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递);
  • Lambda 表达式可以写出更简洁,更灵活的代码;
// Lambda 表达式入门程序
public class TestLambda{
List<Employee> employees = Arrays.asList(
new Employee("张三",16,1000),
new Employee("李四",22,2000),
new Employee("熊大",25,1300),
new Employee("熊二",32,1200),
new Employee("赵六",43,3200)
); @Test
public void test2(){
List<Employee> list = filterEmpByAge(employees); for(Employee emp : list){
System.out.println(emp);
}
} // 需求一: 获取当前公司中,员工年龄大于等于30的员工信息
public List<Employee> filterEmpByAge(List<Employee> list){
List<Employee> emps = new ArrayList<>(); for(Employee emp : list){
if(emp.getAge() >= 30){
emps.add(emp);
}
}
return emps;
} // 需求二: 获取当前公司中,员工工资大于等于2000的员工信息
public List<Employee> filterEmpBySal(List<Employee> list){
List<Employee> emps = new ArrayList<>(); for(Employee emp : list){
if(emp.getSalary() >= 2000){
emps.add(emp);
}
}
return emps;
} // 优化方式一: 策略设计模式
@Test
public void test3(){
// 按年龄过滤
List<Employee> list = filterEmployee(employees,new FilterEmployeeByAge()); for(Employee employee : list){
System.out.println(employee);
} // 按工资过滤
List<Employee> list2 = filterEmployee(employees,new FilterEmployeeBySal()); for(Employee employee : list2){
System.out.println(employee);
}
} public List<Employee> filterEmployee(List<Employee> list, MyPredicte<Employee> mp){
List<Employee> emps = new ArrayList<>(); for(Employee employee : list){
if(mp.test(employee)){
emps.add(employee);
}
}
} // 优化方式二: 匿名内部类
// 不再需要创建泛型接口的实现类
@Test
public void test4() {
// filterEmployee(employees, 匿名内部类);
List<Employee> list = filterEmployee(employees, new MyPredicate<Emplooyee>(){
public boolean test(Employee emp){
return emp.getSalary() <= 2000;
}
}); for(Employee employee : list){
System.out.println(employee);
}
} // 优化方式三: Lambda 表达式
@Test
public void test5(){
List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 2000);
list.forEach(System.out::println);
} // 优化方式四: Stream API
@Test
public void test6(){
employees.stream()
.filter((e) -> e.getSalary() <= 2000)
.forEach(System.out::println); // 获取所有员工的名字
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
} // 创建泛型接口
public interface MyPredicate<T>{
public boolean test(T t);
} // 创建泛型接口的实现类
public class filterEmpByAge implements MyPredicate<Employee> { public boolean test(Employee emp){
return emp.getAge() >= 30;
}
} public class filterEmpBySal implements MyPredicate<Employee> { public boolean test(Employee emp){
return emp.getSalary() >= 2000;
}
}

2. Lambda 表达式基础语法

  1. ->: 该操作符称为箭头操作符或Lambda 操作符,将Lambda 表达式拆分成两部分:

    • 左侧: Lambda 表达式的参数列表;
    • 右侧: Lambda 表达式所需执行的功能,即 Lambda 体;
  2. 语法格式一: 无参数,无返回值
    • () -> System.out.println("Hello Lambda!");
  3. 语法格式二: 有一个参数,无返回值;
    • (x) -> System.out.println(x);
    • 或者 x -> System.out.println(x); 若只有一个参数,小括号可以省略不写;
  4. 语法格式三: 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句;
  5. Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即"类型推断";
    • (Integer x, Integer y) -> Integer.compare(x,y);其中,数据类型 Integer,可以省略不写;
// 测试类
public class TestLambda{ @Test
public void test01(){
int num = 0; // JDK 1.7 之前,必须是final,才能在匿名函数内部使用
// JDK 1.8 可以不使用 final, 但是在匿名函数内部仍然不能进行运算 // 无参数,无返回值
// 1. Java8 之前写法:
Runnable r = new Runnable(){
public void run(){
System.out.println("Hello World!" + num);
}
};
r.run(); // Lambda 表达式
Runnable r2 = () -> System.out.println("Hello World!");
r2.run(); } @Test
public void test02(){
// 有两个以上的参数,有返回值,并且 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); }
}

3. Lambda 表达式需要"函数式接口"的支持

  • 函数式接口:接口中只有一个抽象方法时,称为函数式接口;
  • 可以使用注解@FunctionalInterface进行修饰,这样,可以检查该接口是否是函数式接口;
// Lambda 练习
// 声明一个带两个泛型的函数式接口,泛型类型为<T,R>, T 为参数, R 为返回值;
// 接口中声明对应抽象方法;
// 在 TestLambda 类中声明方法,使用接口作为参数,计算两个 long 型参数的和与乘积 // 函数式接口
@FunctionalInterface
public interface MyFunction<T,R>{
public R getValue(T t1, T t2);
} // 测试类
public class TestLambda{
public void option(Long l1, Long l2, MyFunction<Long,Long> mf){
System.out.println(mf.getValue(l1,l2));
} @Test
public void test(){
option(100L,200L,(x,y) -> x+y); option(100L,200L, (x,y) -> x*y);
}
}

4. 四大内置核心函数式接口

  1. 消费型接口: Consumer<T>

    • 参数类型: T
    • 返回值类型: void
    • 用途: 对类型为T的对象进行操作,包含方法: void accept(T t)
  2. 供给型接口: Supplier<T>
    • 参数类型: 无
    • 返回值类型: T
    • 用途: 返回类型为T的对象,包含方法: T get()
  3. 函数型接口: Function<T,R>
    • 参数类型: T
    • 返回值类型: R
    • 对类型为T的对象进行操作,并返回结果,结果是R类型的对象,包含方法: R apply(T t)
  4. 断言型接口: Predicate<T>
    • 参数类型: T
    • 返回值类型: boolean
    • 确定类型为T的对象是否满足某约束,并返回boolean值;包含方法:boolean test(T t)

5. 方法引用

  1. 方法引用: 若 Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用";

    可以理解为,方法引用是 Lambda 表达式的另外一种表现形式;
  2. 主要有三种语法格式:
    • 对象::实例方法名
    • 类::静态方法名
    • 类::实例方法名
    • 注意: Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
    • 注意2: 若 Lambda 参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用

      ClassName::method方式调用;

5.1 构造方法引用

  • ClassName::new
  • 注意: 需要调用的构造器参数列表要与函数式接口中抽象方法的参数列表保持一致!

5.2 数组引用

  • Type::new
public class TestMethodRef{

    @Test
public void test(){
Consumer<String> con = (x) -> System.out.println(x);
con.accept("测试方法...."); //对象::实例方法名
Consumer<String> con2 = System.out::println;
con2.accept("测试方法"); // 示例二: 获取员工姓名
Employee emp = new Employee();
Supplier<String> sup = () -> emp.getName();
String str = sup.get();
System.out.println(str); Supplier<String> sup2 = emp::getName;
String str2 = sup2.get();
System.out.println(str2);
} @Test
public void test2(){
// 类::静态方法名
Comparator<Integer> com = (x,y) -> Integer.compare(x,y); Comparator<Integer> com2 = Integer::compare;
} @Test
public void test3(){
// 类::实例方法名
BiPredicate<String,String> bp = (x,y) -> x.equals(y); Bipredicate<String,String> bp2 = String::equals;
} @Test
public void test4(){
Supplier<Employee> sup = () -> new Employee(); // 构造器引用(无参构造器)
Supplier<Employee> sup2 = Employee::new; Function<Integer,Employee> fun = (x) -> new Employee(x); // 构造器引用(有一个参数的构造器)
Function<Integer,Employee> fun = Employee::new;
} @Test
public void test5(){
Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length); // 数组方式的引用
Function<Integer,String[]> fun2 = String[]::new;
}
}

参考资料

Java8 新特性之Lambda表达式的更多相关文章

  1. java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合

    java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...

  2. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  3. Java8新特性之Lambda表达式

    lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...

  4. 【Java8新特性】Lambda表达式基础语法,都在这儿了!!

    写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...

  5. 【Java8新特性】- Lambda表达式

    Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...

  6. 夯实Java基础(二十二)——Java8新特性之Lambda表达式

    1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...

  7. java8新特性之——lambda表达式的使用

    lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...

  8. 【Java8新特性】Lambda表达式

    一.Lambda 表达式 是什么? Lambda读音:拉姆达. Lambda是一个匿名函数,匿名函数就是一个没有名字的函数. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). ...

  9. Java8 新特性(一)- Lambda 表达式

    2014年3月18日发布了JavaSE 8 不追求技术的新,追求技术的稳定 本质:Lambda 表达式是一个匿名函数 作用:简化代码,增强代码的表达力 Lambda 语法格式 // 格式1:无参无返回 ...

随机推荐

  1. python学习笔记(7)--爬虫隐藏代理

    说明: 1. 好像是这个网站的代理http://www.xicidaili.com/ 2. 第2,3行的模块不用导入,之前的忘删了.. 3. http://www.whatismyip.com.tw/ ...

  2. TF和SD

    TF卡又称T-Flash卡,全名:TransFLash,又名:Micro SD SD卡(Secure Digital Memory Card,安全数码卡)

  3. Httpclient远程调用WebService示例(Eclipse+httpclient)

    package cn.com.taiji.pos.httpserver; import java.io.BufferedInputStream;import java.io.ByteArrayOutp ...

  4. CSS3 实现的一个简单的"动态主菜单" 示例

    其实这个示例蛮无聊的 很简单 也没什么实际的用处. 主要是展示了 CSS3 如何实现动画效果. 写这个主要是想看一看 完成这样的效果 我到底要写多少代码. 同时和我熟悉的java做个比较. 比较结果不 ...

  5. Differential Geometry之第九章常平均曲率曲面

    第九章.常平均曲率曲面 1.Hopf微分与Hopf定理 等温坐标系(isothermal coordinate system)曲面上的一种特殊坐标系.若曲面的第一基本形式I在坐标系(u,v)下可以写成 ...

  6. ThinkPHP中的验证码不出现的解决办法

    出现这种问题的原因可能是因为代码写的不规范,出现了其他的输出:解决办法: 原代码:     public function captchaAction()    {        $verify = ...

  7. css图标

    一.介绍 采用这种字体,我们可以避免网站制作中采用好多图片,一方面解决了浏览器的兼容性问题.另一方面,这些字体都是矢量字体,我们只要在调整这些图标时,将他们的字体大小以及颜色,我们就可以解决很多不是图 ...

  8. 用Powershell调用DLL文件

    http://blog.csdn.net/itanders/article/details/5702771

  9. IOS6.0调用通讯录和之前的差别

    6.通讯录列表获取差异 自iOS6.0后获取通讯录列表需要询问用户,经过用户同意后才可以获取通讯录用户列表.而且ABAddressBookRef的初始化工作也由ABAddressBookCreate函 ...

  10. 那个你经常用的abs函数(取绝对值)真的总是返回非负数吗?

    前几天在牛客网看到一道关于abs()函数返回值的题目,见下图,当时还没反应过来,第一反应是:自从我开始学C语言,就知道它是用来求int数的绝对值的,返回值当然是0或者正数啊,一看答案就是A. 后来思来 ...