24、lambda表达式
一、Lambda表达式的介绍
Lambda表达式是 Java8 中最重要的新功能之一。使用 Lambda 表达式可以替代只有一个抽象函数的接口实现,
告别匿名内部类,代码看起来更简洁易懂。Lambda表达式同时还提升了对集合、框架的迭代、遍历、过滤数据的操作。
特点:
1:函数式编程
2:参数类型自动推断
3:代码量少,简洁
二、Lambda表达式的使用
public class LambdaDemo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("running....."); } }); thread.start(); new Thread(()->{System.out.println("running2.....");}).start(); } }
打印结果为:
/* running..... running2..... Process finished with exit code 0 */
public class LambdaDemo { public static void main(String[] args) { List<String> list = Arrays.asList("java","javascript","scala","python"); Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length()-o2.length(); } }); for(String str:list){ System.out.println(str); } Collections.sort(list,(a,b)->a.length()-b.length()); list.forEach(System.out::println); } }
打印结果:
/* java scala python javascript java scala python javascript Process finished with exit code 0 */
对比一下Lambda表达式更加简洁
三、函数式接口
只有一个抽象方法(Object类中的方法除外)的接口是函数式接口
public class Student { private String name; private int age; private int score; public Student() { } public Student(String name, int age, int score) { this.name = name; this.age = age; this.score = score; } @Override public String toString() { return "student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}'; } }
public class Test { public static void main(String[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("zhangsan",14,67)); list.add(new Student("lisi",13,89)); list.add(new Student("wangwu",15,97)); list.add(new Student("maliu",12,63)); list.add(new Student("zhaoqi",17,75)); //查找年龄大于14的学生 findByAge(list); System.out.println("---------------------"); //查找分数大于75的学生 findByScore(list); } public static void findByAge(ArrayList<Student> students){ ArrayList<Student> list =new ArrayList<>(); for(Student stu:students){ if(stu.getAge()>14){ list.add(stu); } } for(Student student :list){ System.out.println(student); } } public static void findByScore(ArrayList<Student> students){ ArrayList<Student> list =new ArrayList<>(); for(Student stu:students){ if(stu.getScore()>75){ list.add(stu); } } for(Student student :list){ System.out.println(student); } } }
两个方法体基本都是重复代码
改版1:
import com.mashibing.why.Student; public interface StudentFilter { boolean compare(Student student); }
public class AgeFilter implements StudentFilter { @Override public boolean compare(Student student) { return student.getAge()>14; } }
public class ScoreFilter implements StudentFilter { @Override public boolean compare(Student student) { return student.getScore()>75; } }
public class Test { public static void main(String[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("zhangsan",14,67)); list.add(new Student("lisi",13,89)); list.add(new Student("wangwu",15,97)); list.add(new Student("maliu",12,63)); list.add(new Student("zhaoqi",17,75)); getByFilter(list,new AgeFilter()); getByFilter(list,new ScoreFilter()); } public static void getByFilter(ArrayList<Student> students,StudentFilter filter){ ArrayList<Student> list = new ArrayList<>(); for(Student student:students){ if(filter.compare(student)){ list.add(student); } } printStudent(list); } public static void printStudent(ArrayList<Student> students){ for(Student student:students){ System.out.println(student); } } }
定义接口, 易扩展
1、通过年龄判断, 2、通过分数判读,如果现在通过名称长度判读,还需要实现子类
改版2:
public class Test { public static void main(String[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("zhangsan",14,67)); list.add(new Student("lisi",13,89)); list.add(new Student("wangwu",15,97)); list.add(new Student("maliu",12,63)); list.add(new Student("zhaoqi",17,75)); getByFilter(list, new StudentFilter() { @Override public boolean compare(Student student) { return student.getAge()>14; } }); getByFilter(list, new StudentFilter() { @Override public boolean compare(Student student) { return student.getScore()>75; } }); System.out.println("-------------------"); getByFilter(list, new StudentFilter() { @Override public boolean compare(Student student) { return student.getName().length()>5; } }); } public static void getByFilter(ArrayList<Student> students, StudentFilter filter){ ArrayList<Student> list = new ArrayList<>(); for(Student student:students){ if(filter.compare(student)){ list.add(student); } } printStudent(list); } public static void printStudent(ArrayList<Student> students){ for(Student student:students){ System.out.println(student); } } }
改版3:
public class Test { public static void main(String[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("zhangsan",14,67)); list.add(new Student("lisi",13,89)); list.add(new Student("wangwu",15,97)); list.add(new Student("maliu",12,63)); list.add(new Student("zhaoqi",17,75)); getByFilter(list,(e)->e.getAge()>14 ); getByFilter(list, (e)->e.getScore()>75); System.out.println("-------------------"); getByFilter(list, (e)->e.getName().length()>5); } public static void getByFilter(ArrayList<Student> students, StudentFilter filter){ ArrayList<Student> list = new ArrayList<>(); for(Student student:students){ if(filter.compare(student)){ list.add(student); } } printStudent(list); } public static void printStudent(ArrayList<Student> students){ for(Student student:students){ System.out.println(student); } } }
四、Lambda表达式的使用语法
public class LambdaTest { public static void main(String[] args) throws Exception { Runnable runnable = new Runnable() { @Override public void run() { System.out.println("running1 ....."); } }; runnable.run(); Runnable runnable2 = ()->{ System.out.println("running2...."); }; runnable2.run(); Runnable runnable3 = ()-> System.out.println("running3...."); runnable3.run(); }
打印结果为:
/* running1 ..... running2.... running3.... */
1、()参数的个数,根据函数式接口里面抽象的参数个数来决定,当参数只有一个的时候,()可以省略
2、当expr逻辑非常简单的时候,{}和return可以省略
1、表达式案例
()->{}
()->{System.out.println(1);}
()->System.out.println(1)
()->{return 100;}
()->100
()->null
(int x)->{return x+1;}
(int x)->x+1
(x)->x+1
x->x+1
2、不同的写法
2.1、实例1:
public class LambdaTest { public static void main(String[] args) throws Exception { Callable<String> c1 = new Callable() { @Override public String call() throws Exception { return "mashibing"; } }; System.out.println(c1.call()); Callable<String> c2 = ()->{return "mashibing2";}; System.out.println(c2.call()); Callable<String> c3 = ()->"mashibing3"; System.out.println(c3.call()); }
打印结果为:
/* mashibing mashibing2 mashibing3 */
2.2、实例2:
@FunctionalInterface public interface StudentDao { void insert(Student student); }
public class Student { }
public class LambdaTest { public static void main(String[] args) throws Exception { StudentDao sd1 = new StudentDao() { @Override public void insert(Student student) { System.out.println("插入学生1"); } }; StudentDao sd2 = (student)->{ System.out.println("student: "+student); }; StudentDao sd3 = (Student student)-> System.out.println("student3:"+student); sd1.insert(new Student()); sd2.insert(new Student()); sd3.insert(new Student()); }
2.3、实例3:
@FunctionalInterface public interface TeacherDao { int get(Teacher teacher); }
public class Teacher { }
public class LambdaTest { public static void main(String[] args) throws Exception { TeacherDao td1 = new TeacherDao() { @Override public int get(Teacher teacher) { return 1; } }; TeacherDao td2 = (teacher)->{return 2;}; TeacherDao td3 = (Teacher teacher)->{return 3;}; TeacherDao td4 = (teacher)->4; TeacherDao td5 = (Teacher teacher)->5; System.out.println(td1.get(new Teacher())); System.out.println(td2.get(new Teacher())); System.out.println(td3.get(new Teacher())); System.out.println(td4.get(new Teacher())); System.out.println(td5.get(new Teacher()));
2.4、实例4:
Supplier 代表一个输出
Consumer 代表一个输入
BiConsumer 代表两个输入
Function 代表一个输入,一个输出(一般输入和输出是不同类型的)
UnaryOperator 代表一个输入,一个输出(输入和输出是相同类型的)
BiFunction 代表两个输入,一个输出(一般输入和输出是不同类型的)
BinaryOperator 代表两个输入,一个输出(输入和输出是相同类型的)
public class LambdaTest { public static void main(String[] args) throws Exception { /* * 在Java中提供了一系列的函数式接口,用来接受后续传入的逻辑,但是对输入和输出有要求 * * * */ Function<String,Integer> f1 = (str)->{return str.length();}; System.out.println(f1.apply("abcdefg")); Supplier<String> s1 = ()->{return "mashibing";}; Supplier<String> s2 = ()->"mashibing2"; System.out.println(s1.get()); System.out.println(s2.get()); Consumer<String> c11 = (str) -> System.out.println(str); c11.accept("beijing"); System.out.println("---------------"); BiFunction<String,String,Integer> bf = (a,b)->a.length()+b.length(); System.out.println(bf.apply("连老师", "好帅"));
2.5、实例5: 调用
public class LambdaTest { public static void main(String[] args) throws Exception { Runnable runnable1 = ()->get(); Runnable runnable2 = ()->exec(); // Runnable runnable3 = ()->100; 不行100 是返回值 // Runnable runnable4 = ()->""; runnable1.run(); } static int get(){ return 1; } static String find(){ return "find"; } static void exec(){ find(); } }
2.6、实例6
public interface LamabdInterface { int get(); }
public class LambdaTest { public static void main(String[] args) throws Exception { com.mashibing.lambda.LamabdInterface li1 = ()->get(); // com.mashibing.lambda.LamabdInterface li2 = ()->find(); 是一个字符串 明确了要是一个int com.mashibing.lambda.LamabdInterface li3 = ()->100; // LamabdInterface li4 = ()->"abc"; com.mashibing.lambda.LamabdInterface li5 = ()->true?1:0; System.out.println(li1.get()); } static int get(){ return 1; } static String find(){ return "find"; } static void exec(){ find(); } }
五、方法的引用
▪ 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,
方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现
恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用
什么意思???
public class Test1 { public static void main(String[] args) { Function<String,Integer> f1 = (str)->{return str.length();}; System.out.println(f1.apply("abc")); Consumer<String> c = (str)-> System.out.println(str); c.accept("str"); } }
1、静态方法引用
public class Test2 { static String put(){ System.out.println("put....."); return "put"; } public static void main(String[] args) { // System.out.println(put()); Supplier<String> s1 = ()->Test2.put(); System.out.println(s1.get()); Supplier<String> s2 = Test2::put; System.out.println(s2.get()); } }
另一种方式
public class Test2 { public static void main(String[] args) { Supplier<String> s3 = Fun::hehe; System.out.println(s3.get()); } } class Fun{ public static String hehe(){ return "hehe"; } }
public class Test2 { public static String toUpperCase(String str){ return str.toUpperCase(); } public static void main(String[] args) { Function<String,String> f1 = (str)->str.toUpperCase(); Function<String,String> f2 = (str)->Test2.toUpperCase(str); Function<String,String> f3 = Test2::toUpperCase; Function<String,String> f4 = Fun::toUpperCase; System.out.println(f1.apply("abc")); System.out.println(f2.apply("abc")); System.out.println(f3.apply("abc")); System.out.println(f4.apply("abc")); } } class Fun{ public static String toUpperCase(String str){ return str.toUpperCase(); } }
public class Test2 { public static Integer getLength(String str,String str2){ return str.length()+str2.length(); } public static void main(String[] args) { BiFunction<String,String,Integer> bf = (a,b)->a.length()+b.length(); BiFunction<String,String,Integer> bf2 = Test2::getLength; System.out.println(bf2.apply("abc", "def")); System.out.println(bf.apply("abc", "def")); } }
public class Test2 { public static void getSize(int size){ System.out.println(size); } public static void main(String[] args) { Consumer<Integer> c1 = Test2::getSize; Consumer<Integer> c2 = (size)->Test2.getSize(size); c1.accept(123); } }
2、实例方法引用
如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用
示例1:无参
public class Test3 { public String put(){ return "put..."; } public static void main(String[] args) { System.out.println(new Test3().put()); Supplier<String> s1 = ()->new Test3().put(); Supplier<String> s2 = ()->{return new Test3().put();}; Supplier<String> s3 = new Test3()::put; System.out.println(s1.get()); System.out.println(s2.get()); System.out.println(s3.get()); } }
示例2:一个输入
public class Test3 { public void getSize(int size){ System.out.println("size:"+size); } public static void main(String[] args) { //唯一的创建一个test3对象 Test3 test = new Test3(); Consumer<Integer> c1 = (size)->new Test3().getSize(size); Consumer<Integer> c2 = new Test3()::getSize; Consumer<Integer> c3 = test::getSize; c1.accept(123); c2.accept(123); c3.accept(123); } }
示例3:一个输入一个输出
public class Test3 { public String toUpperCase(String str){ return str.toUpperCase(); } public static void main(String[] args) { Function<String,String> f1 = (str)->str.toUpperCase(); Function<String,String> f2 = (str)->test.toUpperCase(str); Function<String,String> f3 = new Test3()::toUpperCase; Function<String,String> f4 = test::toUpperCase; System.out.println(f1.apply("abc")); System.out.println(f2.apply("abc")); System.out.println(f3.apply("abc")); System.out.println(f4.apply("abc")); } }
3、对象方法引用
抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。
如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用
示例1:
class Too{ public Integer fun(String s){ // 带参数 有返回值 return 1; } public void foo(){ System.out.println("foo"); // 无参 无返回值 } } class Too2{ public Integer fun(String s){ // 带参数 有返回值 return 1; } public void foo(){ System.out.println("foo---too2"); // 无参 无返回值 } public void show(String str){ System.out.println("show ---too2"+str); // 带参数 无返回值 } }
public class Test4 { public static void main(String[] args) { Consumer<Too> c1 = (Too too)->new Too().foo(); c1.accept(new Too()); // Consumer<Too> c2 = (Too too) ->new Too2().show(); // c2.accept(new Too()); Consumer<Too> c3 = Too::foo; c3.accept(new Too()); } }
4、构造方法引用
如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
package com.mashibing.functionref; import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; public class Test5 { public static void main(String[] args) { Supplier<Person> s1 = ()->new Person(); s1.get(); Supplier<Person> s2 = Person::new; s2.get(); Supplier<List> s3 = ArrayList::new; Supplier<Set> s4 = HashSet::new; Supplier<Thread> s5 = Thread::new; Supplier<String> s6 = String::new; Consumer<Integer> c1 = (age)->new Account(age); Consumer<Integer> c2 = Account::new; c1.accept(123); c2.accept(456); Function<String,Account> f1 = (str)->new Account(str); Function<String,Account> f2 = Account::new; f1.apply("abc"); f2.apply("def"); } } class Account{ public Account(){ System.out.println("调用无参构造方法"); } public Account(int age){ System.out.println("age 参数构造" +age); } public Account(String str){ System.out.println("str 参数构造" +str); } } class Person{ public Person(){ System.out.println("调用无参的构造方法"); } }