lambda表达式
@FunctionalInterface
函数式接口的注解
函数式接口中只能有一个抽象方法,并不是只能有一个方法。
1、基础使用
2、引用方法
方法归属者 : : 方法名
静态方法的归属者是类,普通方法的归属者是对象
package com.chen.lambda;
/**
* lambda表达式引用方法
*/
public class Test {
public static void main(String[] args) {
//引用本类中的静态方法
ReturnOneParam returnOneParam = Test::doubleNum;
int result = returnOneParam.method(20);
System.out.println(result);
//引用本类中的非静态方法
Test test = new Test();
ReturnOneParam returnOneParam1 = test::addTwo;
int result1 = returnOneParam1.method(10);
System.out.println(result1);
//引用非本类中的静态方法
ReturnOneParam returnOneParam3 = Test1::treble;
int result3 = returnOneParam3.method(20);
System.out.println(result3);
//引用非本类中的非静态方法
Test1 test1 = new Test1();
ReturnOneParam returnOneParam2 = test1::addThree;
int result2 = returnOneParam2.method(10);
System.out.println(result2);
}
/**
* lambda表达式的方法体中使用引用方法的要求:
*
* 引用的方法和函数式接口中抽象方法
* 1、返回值类型一致
* 2、参数类型、参数个数一致
*/
public static int doubleNum(int a){
return 2*a;
}
public int addTwo(int a){
return a+2;
}
}
/**
* 一个有返回值、一个参数的函数式接口
*/
interface ReturnOneParam{
int method(int a);
}
3、创建线程
package com.chen.lambda;
/**
* lambda表达式实现Runnable接口的run()方法
*/
public class Test2 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+" 开始");
new Thread(()->{
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+i);
}
},"lambda thread").start();
System.out.println(Thread.currentThread().getName()+" 结束");
}
}
4、操作集合
1、遍历集合
package com.chen.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class Test3 {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
ConsumerImp c = new ConsumerImp();
/**
* default void forEach(Consumer<? super T> action) {
* Objects.requireNonNull(action);
* for (T t : this) {
* action.accept(t);
* }
* }
*/
list.forEach(c);
}
}
/**
* Consumer是一个函数式接口
*/
class ConsumerImp implements Consumer{
@Override
public void accept(Object o) {
System.out.println(o);
}
}
简化的原理
- Consumer是一个函数式接口,该接口的抽象方法是accept( T t)
- forEach( )方法遍历出的每个元素传递到accept( T t)方法中执行一个操作
- 如果只需要输出该元素,即System.out.println( t )
- accept( T t)和 println( t )两个方法都没有返回值、只有一个参数、且参数类型相同(在此处)
- 所以引用 println( t )方法作为 accept( T t)的实现
- println( t )方法不是静态方法,需要由PrintStream类的一个对象调用
- out 刚好是一个PrintStream类的静态属性,所以用来表示println( t )方法的归属者PrintStream类
【疑问】out是PrintStream类的一个属性,并不是对象!静态属性从属于类,可通过静态属性找到类?这么理解?
package com.chen.lambda;
import java.util.ArrayList;
import java.util.List;
public class Test3 {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//简化版甚至都不需要传递打印的内容
list.forEach(System.out::println);
}
}
2、删除元素
package com.chen.lambda;
import java.util.ArrayList;
import java.util.List;
public class Test4 {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.removeIf((ele)->{
return ele.equals("b");
});
//简化
list.removeIf(ele->ele.equals("b"));
list.forEach(System.out::println);
}
}
原理
-
函数式接口Predicate的 抽象方法 boolean test(T t)
-
传入一个参数,返回布尔值
-
实现:
传入元素——迭代器迭代的每个元素
返回布尔值——equals( )方法,迭代的每个元素和目标元素对比
/**
* 原始的写法
*/
list.removeIf((ele)->{
return ele.equals("b");
});
/**
* 简化的写法
*/
list.removeIf(ele->ele.equals("b"));
3、元素排序
package com.chen.lambda;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* 1、通过传入比较器的方法
* 2、通过lambda表达式
*/
public class Test5 {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("b");
list.add("c");
list.add("a");
list.add("d");
//list.sort(new MyComparator());
list.sort((o1,o2)->o1.compareTo(o2));
list.forEach(System.out::println);
}
}
class MyComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
}
5、闭包问题
闭包的本质是代码片段,也可以理解为一个代码片段的引用。在java中匿名内部类也是闭包的一种实现方式。
在闭包中访问外部的变量时,外部变量必须是final 修饰的,虚拟机也会帮我们自动加上final关键字。
package com.chen.lambda;
public class Test6 {
public static void main(String[] args) {
final int n = 10;
A a = ()->System.out.println(n);;
a.method();
//n++;
}
}
/**
* 定义一个无返回值、无参数的函数式接口
*/
interface A{
void method();
}