jdk1.8 自从其发布以来一直都是 Java 开发的一个主要版本,其新增了非常多的特性,支持函数式编程
而 Lambda 表达式则是 jdk1.8 的一个核心之一
Lambda 表达式是一个匿名函数,可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更加简洁、灵活的代码。作为一种更为紧凑的代码风格,使 Java 语言表达能力得到提升
语法糖:指使用更加f方便,但是原理不变的代码语法。例如在遍历集合时使用的 for-each 语法,其底层的实现原理仍然是迭代器。从应用层面上讲,Java 中d的 Lambda 表达式可以被当作匿名内部类的语法糖,但是二者在原理上是不同的。
以下是 Lambda 表达式的重要特征
语法对比
匿名内部类demo
//原来的匿名内部类
Comparator com = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return Integer.compare(o1, o2);
}
};
TreeSet ts = new TreeSet<>(com);
使用 lambda 表达式改写
Comparator com = (x,y) -> Integer.compare(x, y);
TreeSet ts = new TreeSet<>(com);
需求,按按条件查询数据
如:获取学生中年龄大于 20 的信息
创建实体类Student
package com.jiker.bean;
public class Student {
private Integer id;
private String sName;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", sName=" + sName + ", age=" + age + "]";
}
public Student(Integer id, String sName, Integer age) {
super();
this.id = id;
this.sName = sName;
this.age = age;
}
}
由于本次实验不涉及数据库的操作,可以将学生信息存储在一个 List 中
java.util.List list = Arrays.asList(
new Student(1, "zhangsan", 19),
new Student(2, "lisi", 22),
new Student(3, "wangwu", 20),
new Student(4, "zhaoliu", 17),
new Student(5, "liuqi", 21)
);
1、原始方法
public java.util.List filterStudent(java.util.List list){
java.util.List stu = new ArrayList<>();
for (Student student : list) {
if (student.getAge() > 20) {
stu.add(student);
}
}
return stu;
}
若此时,还有一个需求即查找 id 大于 2 的学生信息,则代码为
public java.util.List filterStudent2(java.util.List list){
java.util.List stu = new ArrayList<>();
for (Student student : list) {
if (student.getId() > 20) {
stu.add(student);
}
}
return stu;
}
可以看到,两者仅有 if 判断条件中的语句不一样
此时,若项目中有多种类似需求时,则会出现大量的冗余代码
2、优化方式1:定义接口(策略设计模式)
//接口定义
package com.jiker.predicate;
public interface MyPredicate {
public boolean test(T t);
}
实现类过滤器
package com.jiker.predicate;
import com.jiker.bean.Student;
public class FilterStudentByAge implements MyPredicate {
@Override
public boolean test(Student student) {
// TODO Auto-generated method stub
return student.getAge() > 20;
}
}
public List filerStud(List list,MyPredicate mp){
List students = new ArrayList<>();
for (Student student : list) {
if (mp.test(student)) {
students.add(student);
}
}
return students;
}
//测试
List students = filerStud(list, new FilterStudentByAge());
for (Student student : students) {
System.out.println(student);
}
不足:每次实现一个新的需求时,都需要新创建一个 MyPredicate 的实现类
3、优化方式2:匿名内部类
List students = filerStud(list, new MyPredicate() {
@Override
public boolean test(Student t) {
// TODO Auto-generated method stub
return t.getAge() > 20;
}
});
for (Student student : students) {
System.out.println(student);
}
4、优化方式3:Lambda 表达式
//Lambda表达式
List students = filerStud(list, (e) ->e.getAge() > 20);
list.forEach(System.out::println);
Java 8 中引入了一个新的操作符:"->"
,该操作符称为箭头操作符或 Lambda 操作符
箭头操作符将 Lambda 表达式拆分成两部分
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需执行的功能,即: Lambda 体
语法格式一:无参数、无返回值
() -> System.out.println("无返回值");
如:
//原始方式
Runnable r = new Runnable(){
@Override
public void run(){
System.out.print("run ...");
}
}
r.run();
//改写
Runnable r = () -> System.out.print("run ...");
r.run();
注意事项:若在局部内部类中应用了一个同级别的变量,在 JDK1.7
中,该变量需要是 final
类型
而在 JDK1.8
中,不需要定义变量为 final
类型,但仍然不能修改变量的值,同时 Lambda 表达式也得遵守这一规则
int num = 0;
Runnable r = () -> System.out.print("run ..." + num); //编译通过
Runnable r = () -> System.out.print("run ..." + num++); //编译报错
语法格式二:有参数,无返回值
若只有一个参数,小括号可以不写
Consumer con = (x) -> System.out.print(X);//推荐使用
Consumer con = x -> System.out.print(X);
con.accept("Lambda语法")
语法格式三:有参数,有返回值
若 Lambda 体中有多条语句,则需要使用大括号
若仅有一条返回语句,则大括号和 return 关键字都可省略
Comparator com = (x,y) -> {
System.out.println("使用大括号");
return Integer.compare(x,y);
}
语法格式四:Lambda 表达式的数据类型可以省略不写
因为 JVM 的编译器可以通过上下文推断出数据类型,称为 “类型推断”
相同原理:
String[] str = {"a","b","c"};
List list = new ArrayList<>(); //JDK1.7
//JDK1.8
public void show(Map map){}
show(new HashMap<>());
... ...
函数式接口 (Functional Interface) 也是 Java 8 的另一个新特性
函数式接口:在接口中有且只有一个抽象方法,但可以有多个非抽象方法的接口(默认、静态、私有)
函数式接口,即适用于函数式编程场景的接口。而 Java 中的函数式编程体现就是 Lambda,所以函数式接口就是可以适用于 Lambda 使用的接口。只有确保接口中有且仅有一个抽象方法,Java 中的 Lambda 表达式才能顺利地进行推导
格式:
只要确保接口中有且仅有一个抽象方法即可
修饰符 interface 接口名称{
public abstract 返回值类型 方法名称(可选参数信息)l
//其他非抽象方法内容
}
由于接口中抽象方法的 public abstract
是可以省略的,所以定义一个函数式接口非常简单
public interface MyFunctionalInterface{
void myMethod();
}
同时,可以使用注解 @FunctionalInterface
加在某一接口上,检查该接口是否为一个函数式接口
/**
* An informative annotation type used to indicate that an interface
* type declaration is intended to be a functional interface as
* defined by the Java Language Specification.
* /
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer< T> 消费型接口 | T | void | 对类型为 T 的对象应用操作,包含方法 void accept(T t) |
Supplier< T> 供给型接口 | 无 | T | 返回类型为 T 的对象,包含方法 T get() |
Function< T,R> 函数型接口 | T | R | 对类型为 T 的对象应用操作,并返回结果。结果是 R 类型的对象,包含方法 R apply(T t) |
Predicate< T> 断定型接口 | T | boolean | 确定类型为 T 的对象是否满足某约束,并返回 boolean 值,包含方法 boolean testt(T t) |
Example1:消费型接口
@Test
public void test1(){
cons(1000,(m) -> System.out.println("消费 " + m));
}
public void cons(Integer money,Consumer con){
con.accept(money)
}
Example2:供给型接口
//产生一些整数,放入集合
public List getList(int num Supplier sup){
List list = new ArrayList<>();
for(int i = 0;i < num;i++){
Interger n = sup.get();
list.add(n);
}
return list;
}
@Test
public void test2(){
List list = getList(10,() -> (int)(Math.random() * 100));
}
Example3:函数型接口
//处理字符串
public String strHandler(String str,Function fun){
return fun.apply(str);
}
@Test
public void test3(){
String str = strHandler("\t\t\t Lambda ",(str) -> str.trim);
}
Example4:断定型接口
//将满足条件的字符串f放入集合
public List filterStr(List list,Predicate pre){
List strList = new ArrayList<>();
for(String str : list){
strList.add(str);
}
return strList;
}
@Test
public void test4(){
List list = Arrays,asList("Hello","Jiker","Lambda");
List list2 = filterStr(list,(s) -> s.length() > 3);
}
时间:2019.6.28 19:27