一、应用场景引入

首先编写对应的实体类模拟实际业务:

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Employee {
private String name;
private Integer age;
private double salary;
}

具体数据:

List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 6999.9, Employee.Status.FREE),
new Employee("李四", 38, 3999.9, Employee.Status.BUSY),
new Employee("王五", 50, 5999.9, Employee.Status.VOCATION),
new Employee("赵六", 19, 2999.9, Employee.Status.FREE),
new Employee("田七", 18, 4999.9, Employee.Status.BUSY)
);

此时我们需要得到年龄>=35的所有员工,则可以:

public List<Employee> filterEmployees(List<Employee> employees) {
List<Employee> res = new ArrayList<>();
for (Employee employee : employees) {
if (employee.getAge()>=35){
res.add(employee);
}
}
return res;
} @Test
public void t3() {
List<Employee> res = filterEmployees(employees);
for (Employee employee : res) {
System.out.println(employee);
}
}

但这样可扩展性不好,当我们需要更改过滤条件时则需要新写一个过滤函数,其中有很多相同的代码。

优化一:使用策略模式

先编写一个过滤策略接口:

public interface MyPredicate<t> {
boolean condition(T t);
}

对应的用于过滤年龄的实现类FilterEmployeeByAge

public class FilterEmployeeByAge implements MyPredicate<Employee> {
@Override
public boolean condition(Employee employee) {
return employee.getAge() >= 35;
}
}

然后再编写根据策略进行过滤的函数:

public List<employee> filterEmployees(List<Employee> employees, MyPredicate<Employee> predicate) {
List<Employee> res = new ArrayList<>();
for (Employee employee : employees) {
if (predicate.condition(employee)){
res.add(employee);
}
}
return res;
}

这样我们即可根据不同的策略进行过滤了,如此时我们希望得到年龄>=35的所有员工:

// 策略模式
@Test
public void t4() {
List<Employee> employees = filterEmployees(this.employees, new FilterEmployeeByAge());
for (Employee employee : employees) {
System.out.println(employee);
}
}

若我们希望进行扩展,此时希望得到工资>=3000的所有员工,则可以再编写一个策略实现类,然后再进行相应的策略选择:

// FilterEmployeeBySalary.java
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
@Override
public boolean condition(Employee employee) {
return employee.getSalary() >= 3000;
}
} // MyTest.java
@Test
public void t5() {
List<Employee> employees = filterEmployees(this.employees, new FilterEmployeeBySalary());
for (Employee employee : employees) {
System.out.println(employee);
}
}

但通过这种方法还是比较麻烦,每定义一种过滤条件都需要新建一个类,这时我们可以进一步优化。

优化二:使用匿名内部类

// 匿名内部类
@Test
public void t6() {
List<Employee> employees = filterEmployees(this.employees, new MyPredicate<Employee>() {
@Override
public boolean condition(Employee employee) {
return employee.getAge() > 40;
}
});
for (Employee employee : employees) {
System.out.println(employee);
}
}

这时,我们需要什么样的条件只需要在匿名内部类中进行编写即可,不需要编写新的类,但匿名内部类的形式还是显得不够简洁,可读性不够高。

优化三:使用Lambda表达式

// lambda表达式
@Test
public void t7() {
List<Employee> employees = filterEmployees(this.employees, employee -> employee.getAge() > 30);
employees.forEach(System.out::println);
}

可以看到代码简洁了很多,而且可读性也变高了。

优化四:使用Stream API

在上一步优化中,我们仍需手动定义过滤使用的接口和自定义的过滤函数,那么JDK中有没有直接可以“拿来”的工局呢?Stream API就是JDK中提供的专门用来进行过滤操作的工具,使用方式如下:

// Stream API
@Test
public void t8() {
employees.stream()
.filter(employee -> employee.getSalary() >= 3000)
.forEach(System.out::println);
System.out.println("---------------");
// 得到其中所有的字段
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}

运行结果:

Employee(name=李四, age=38, salary=3999.9)
Employee(name=王五, age=50, salary=5999.9)
Employee(name=田七, age=16, salary=4999.9)
---------------
张三
李四
王五
赵六
田七

二、Lambda运算符和对应语法

语法格式

语法格式一:无参数,无返回值

() -> System.out.println("hello world");

@Test
public void t1() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello world");
}
};
r.run();
System.out.println("-------------------------");
Runnable r1 = () -> System.out.println("Hello Lambda");
r1.run();
}

语法格式二:有一个参数,而且无返回值

(x) -> System.out.println(x);

@Test
public void t2() {
Consumer<String> con = (s) -> System.out.println(s);
con.accept("我大尚硅谷威武");
}

语法格式三:若只有一个参数,小括号可以省略不写

x -> System.out.println(x);

语法格式四:有两个以上的参数,有返回值,且Lambda体中有多条语句

Comparator<Integer> comparator1 = (o1, o2) -> {
System.out.println("函数式接口");
return Integer.compare(o1, o2);
};
@Test
public void t3() {
// 使用匿名内部类
Comparator<Integer> comparator = new Comparator<integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
// 使用Lambda表达式
Comparator<Integer> comparator1 = (o1, o2) -> {
System.out.println("函数式接口");
return Integer.compare(o1, o2);
};
}

语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略

Comparator<Integer> comparator = (o1, o2) -> o1 - o2;

@Test
public void t4() {
Comparator<Integer> comparator = (o1, o2) -> o1 - o2;
int compare = comparator.compare(6, 2);
System.out.println(compare);
}

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,原:

Comparator<Integer> comparator = (Integer o1, Integer o2) -> o1 - o2;

口诀:

左右遇一括号省

左侧类型推断省

Lambda表达式需要“函数式接口”的支持

函数式接口:接口中只有一个抽象方法的接口,可以使用注解@FunctionalInterface进行修饰

三、简单应用

1.调用Collections.sort() 方法,通过定制排序比较两个Employee (先按年龄比,年龄相同按Salary比),使用Lambda作为参数传递。

准备数据:

List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 6999.9),
new Employee("李四", 38, 3999.9),
new Employee("王五", 50, 5999.9),
new Employee("赵六", 19, 2999.9),
new Employee("田七", 18, 4999.9)
);

客户端:

@Test
public void t1() {
employees.sort((o1, o2) -> {
if (o1.getAge() != o2.getAge()) {
return Integer.compare(o1.getAge(), o2.getAge());
} else {
return Double.compare(o1.getSalary(), o2.getSalary());
}
});
employees.forEach(System.out::println);
}

2.①声明函数式接口,接口中声明抽象方法,public String getValue(String str);

②声明类TestLambda ,类中编写方法使用接口作为参数,将一个字符串转换成大写,

并作为方法的返回值。

函数式接口

@FunctionalInterface
public interface MyFunction {
public String getValue(String str);
}

客户端:

public String strHandler(String str, MyFunction mf) {
return mf.getValue(str);
} @Test
public void test2() {
String res = strHandler("abcdefg", str -> str.toUpperCase());
System.out.println(res);
}

3.①声明一个带两个泛型的函数式接口,泛型类型为<t,r> T为参数,R为返回值

②接口中声明对应抽象方法。

③在TestLambda 类中声明方法,使用接口作为参数,计算两个long 型参数的和。

④再计算两个long 型参数的乘积。

函数式接口

@FunctionalInterface
public interface MyFunction2<T> {
public R getValue(T t1, T t2);
}

客户端:

public void op(Long l1, Long l2, MyFunction2<Long, Long> mf) {
System.out.println(mf.getValue(l1, l2));
} @Test
public void t3() {
op(100L, 200L, (t1, t2) -> t1 + t2);
op(100L, 200L, (t1, t2) -> t1 * t2);
}

下一步:Java8 Lambda表达式(二)

Java8 Lambda表达式(一)的更多相关文章

  1. java8 Lambda表达式的新手上车指南(1)

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  2. java8 Lambda表达式的新手上车指南(1)--基础语法和函数式接口

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  3. Java8 Lambda表达式详解手册及实例

    先贩卖一下焦虑,Java8发于2014年3月18日,距离现在已经快6年了,如果你对Java8的新特性还没有应用,甚至还一无所知,那你真得关注公众号"程序新视界",好好系列的学习一下 ...

  4. Java8 Lambda表达式、函数式接口和方法引用

    目录 Java8 Lambda表达式和函数式接口 Lambda表达式 Lambda的使用 函数式接口FunctionalInterface Java内置四大核心函数式接口 方法引用 构造器引用 Jav ...

  5. 【Java学习笔记之三十一】详解Java8 lambda表达式

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

  6. java8 快速入门 lambda表达式 Java8 lambda表达式10个示例

    本文由 ImportNew - lemeilleur 翻译自 javarevisited.欢迎加入翻译小组.转载请见文末要求. Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发 ...

  7. Java8 lambda表达式10个示例

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

  8. Java8 lambda表达式语法 1

    本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人也是刚刚开始学习Java8,所以文中肯定有错误和理解偏差的地方,希望大家帮忙指出,我会持续修改和优化.本文是该系列的第一篇, ...

  9. java8 Lambda表达式的10个例子(转)

    原文:http://jobar.iteye.com/blog/2023477 Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 Java代码 收藏代码// ...

随机推荐

  1. redis淘汰+过期双向保证高可用 | redis 为什么那么快?

    前言 redis和数据相比除了他们的结构型颠覆以外!还有他们存储位置也是不相同.传统数据库将数据存储在硬盘上每次数据操作都需要IO而Redis是将数据存储在内存上的.这里稍微解释下IO是啥意思.IO就 ...

  2. 把 STM32 bluepill 变成调试器(daplink)

    在调一块 ARM M0 内核的板子,使用官方的 DEMO 板子来调,板子上集成了 daplink 调试器. 为了方便使用,我把目标板跟 daplink 剪开了,然后用杜邦线把 daplink 跟目标板 ...

  3. 使用Let’s Encrypt实现网站https化

    使用 Let's Encrypt 证书和搭配 Nginx 实现网站 https 化. 一.SSL证书获取 由于 Let's Encrypy 申请的 SSL 证书只有三个月的有效期,为了实现自动续期,使 ...

  4. 31、服务器磁盘、内存、cpu使用率监控

    31.1.监控磁盘: #!/bin/sh diskspace="`df -hT`" IFS="\n" disk_value="80" ech ...

  5. Spring Boot配置Filter

    此博客是学习Spring Boot过程中记录的,一来为了加深自己的理解,二来也希望这篇博客能帮到有需要的朋友.同时如果有错误,希望各位不吝指教 一.通过注入Bean的方式配置Filter: 注意:此方 ...

  6. 详解 MD5 信息摘要算法

    对于软件研发人员来说 MD5 不是一个陌生的词汇,平时的软件研发中,经常使用 MD5 校验消息是否被篡改.验证文件完整性,甚至将MD5当作加密算法使用. MD5虽不陌生,但不是所有研发人员都了解其算法 ...

  7. head tail 用法

    tail 显示最后几行,-n后面的数字无符号,表示行数 tail -n 1000:显示最后1000行 tail -n +1000:从1000行开始显示到最后 tail -n -1000:从负1000行 ...

  8. linux sort uniq命令详解

    sort 功能说明:将文本文件内容加以排序,sort可针对文本文件的内容,以行为单位来排序. sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+&l ...

  9. Linux创建ftp并设置权限以及忘记ftp帐号(密码)修改 (转)

      忘记ftp密码修改方法:1.登录服务器 cd  /etc/vsftpdcat ftpusers找到对应的ftp用户名 (如果用户名也忘记了 那么 cd /etc 然后cat passwd 查看用户 ...

  10. base64文件解码

    $str = str_replace(' ', '+', $str); //替换空字符串为+$str = str_replace('\n', '',$str); //置空换行符$str = str_r ...