Lambda 介绍
什么是Lambda?
Lambda 表达式是Java 8 重要的新功能之一。使用Lambda 表达式可以替代只有一个抽象函数的接口实现,告别匿名内部类,代码看起来更简洁易懂。Lambda 表达式还提升了对集合、框架的迭代、遍历、过滤数据的操作。
特点
- 函数式编程;
- 参数类型自动推断;
- 代码量少,简洁。
List<String> list = Arrays.asList("java", "javascript", "python", "scala", "nodejs");
// 方式一(jdk 8之前):
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s, String t1) {
return s.length() - t1.length();
}
});
for (String str : list){
System.out.println(str);
}
// 方式二(jdk 8):
Collections.sort(list, (a, b) -> a.length() - b.length());
list.forEach(System.out::println);
应用场景
任何有函数式接口的地方。
什么是函数式接口?
只有一个抽象方法(Object 类中的方法除外)的接口是函数式接口。
引入函数式编程的目的:
- 函数式编程写出的代码简洁且意图明确;
- 多核友好。
常用的函数式接口
Java 中提供了一系列函数式接口,用来接收后续传入的逻辑,但是对输入和输出有要求。
- Supplier 代表一个输出;
- Consumer 代表一个输入;
- BigConsumer 代表两个输入;
- Function 代表一个输入,一个输出;(一般输入和输出是不同类型)
- UnaryOperator 代表一个输入,一个输出;(输入和输出是相同类型)
- BiFunction 代表两个输入,一个输出;(一般输入和输出是不同类型)
- BinaryOperator 代表两个输入、一个输出。(输入和输出是相同类型)
//1. Supplier 代表一个输出
Supplier<String> s1 = ()->{return "hello world!";};
Supplier<String> s2 = ()->"hello world!";
System.out.println(s1.get());
System.out.println(s2.get());
//2. Consumer 一个输入
Consumer<String> consumer = (s)-> System.out.println(s);
consumer.accept("hello world!");
输出结果:
hello world!
//5. Function:一个输入一个输出,输入输出是不同类型
Function<String, Integer> f1 = (s)->{return s.length();};
System.out.println(f1.apply("hello world!"));
输出结果:
12
-------------------------------------------------------------
@Test
public void test01(){
/*
* get() 和exec() 会在Runnable 的run() 方法中执行
* run() 方法是没有返回值的,run() 方法并没有处理get() 的返回值
*/
Runnable r1 = ()->get();
Runnable r2 = ()->exec();
//run() 方法是没有返回值的,这点指定了返回值是100,所以会报错!
// Runnable r3 = ()->100;
r1.run();
r2.run();
}
static int get(){
return 1;
}
static void exec(){
System.out.println("hello world!");
}
输出结果:
hello world!
方法的引用
直接访问类或者实例已经存在的方法或者构造函数方法,方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用使用方法引用。
方法引用的分类
- 静态方法引用 类名::staticMethod
(args)->类名.staticMethod(args) - 实例方法引用 inst::instMethod
(args)->instMethod(args) - 对象方法引用(很少使用) 类名::instMethod
(inst.args)->类名.instMethod(args) - 构造方法引用 类名::new
(args)->new 类名(args)
@Test
public void test01(){
//1. Supplier 代表一个输出;
Supplier supplier = ()->BidSectionTransServiceTest.put();
System.out.println(supplier.get());
//2. 静态方法引用
Supplier<String> supplier1 = BidSectionTransServiceTest::put;
System.out.println(supplier1.get());
}
static String put(){
System.out.println("put......");
return "put";
}
输出结果:
put......
put
- 静态方法的引用:函数式接口的实现恰好可以通过调用一个静态方法来实现
@Test
public void test01(){
BiFunction<String, String, Integer> bf1 = (a, b)-> a.length()+b.length();
BiFunction<String, String, Integer> bf2 = BidSectionTransServiceTest::getLength;
System.out.println(bf1.apply("abc","def"));
System.out.println(bf2.apply("abc","def"));
}
static Integer getLength(String str1, String str2){
return str1.length() + str2.length();
}
- 实例方法的引用:函数式接口恰可以通过调用一个实例的实例方法来实现
@Test
public void test01(){
Consumer<Integer> c1 = (size)->new BidSectionTransServiceTest().getLength(size);
Consumer<Integer> c2 = new BidSectionTransServiceTest()::getLength;
c1.accept(12);
c2.accept(12);
}
void getLength(Integer size){
System.out.println("size: " + size);
}
输出结果:
size: 12
size: 12
- 对象方法引用(用得比较少):抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Launcher.class})// 指定启动类
@Slf4j
public class BidSectionTransServiceTest {
@Test
public void test01(){
Consumer<Too1> c1 = (Too1 t1)->new Too1().foo();
c1.accept(new Too1());
Consumer<Too1> c2 = (Too1 t1)->new Too2().foo();
c2.accept(new Too1());
Consumer<Too1> c3 = Too1::foo;
c3.accept(new Too1());
}
}
class Too1{
public Integer fun(String str){
return 1;
}
public void foo() {
System.out.println("foo1");
}
}
class Too2{
public Integer fun(String str){
return 1;
}
public void foo() {
System.out.println("Too2 =========== foo");
}
public void show(String str){
}
}
输出结果:
foo1
Too2 =========== foo
foo1
- 构造方法的引用:如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
@Test
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Launcher.class})// 指定启动类
@Slf4j
public class BidSectionTransServiceTest {
public void test01(){
Supplier<Student> s1 = ()->new Student();
s1.get();
Supplier<Student> s2 = Student::new;
s2.get();
Supplier<List> s3 = LinkedList::new;
Supplier<Set> s4 = LinkedHashSet::new;
Supplier<Thread> s5 = Thread::new;
Supplier<String> s6 = String::new;
}
}
class Student{
public Student(){
System.out.println("student 的无参构造方法!");
}
}