1、Lambda 表达式
简介:是一个匿名函数,返回了是子定义接口的对象实例
- 注意:不是所有接口都可以使用lambda 表达式,只有当接口里面只有一个需要实现的方法的时候才可以使用lambda表达式,不过并不是代表接口里面只可以写一个接口,在jdk1.8中引入了在接口的里面的方法加上default可以定义为默认的实现空方法
2、简单例子
public class ThreadDemo {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("ok");
}
};
new Thread(runnable).start();
//jdk8中
Runnable runnable1 = () -> System.out.println("ok");
Runnable runnable2 = () -> System.out.println("ok");
System.out.println(runnable1 == runnable2);
new Thread(runnable1).start();
}
}
/*
ok
false
ok
*/
//说明lambda表达式每次返回的都是一个新的对象
Object runnable1 = (Runnable)() -> System.out.println("ok");
Runnable runnable2 = () -> System.out.println("ok");
System.out.println(runnable1 == runnable2);
new Thread((Runnable)runnable1).start();
//说明lambda表达式必须明确的指明返回类型
3、常见的四种写法
@FunctionalInterface//编译器校验,说明该接口是函数接口(单一性责任性)
interface Interface1 {
int doubleNum(int i);
default int add(int x , int y){ //jdk8新增加的接口默认实现方法
return x + y;
}
static int sub(int x , int y){
return x - y;
}
}
public strictfp class LambdaDemo1 {
public static void main(String[] args) {
//第一种
Interface1 i1 = (i) -> i * 2;
Interface1.sub(10, 3);
System.out.println(i1.add(3, 7)); //这里调用并没有什么问题
System.out.println(i1.doubleNum(20));
//这种是最常见写法(当参数为1个的时候可以省略括号)
Interface1 i2 = i -> i * 2;
//可以指明返回值得类型
Interface1 i3 = (int i) -> i * 2;
//需要多个处理的时候可以使用花括号
Interface1 i4 = (int i) -> {
System.out.println("-----");
return i * 2;
};
}
}
4、默认函数接口
//interface IMoneyFormat{
//String format(int i);
//}
class Money{
private final int money;
public Money(int money){
this.money = money;
}
// public void printMoney(IMoneyFormat moneyFormat) {
//System.out.println("我的存款:" + moneyFormat.format(this.money));
// }
//因为labda表达式不需要知道自己实现了什么方法名字,只Function<Integer,String>需知道输入参数是什么类 型以及返回值是什么类型即可
//所以可以不用写接口并且可以使用jdk8自带的默认函数Function<Integer,String> Integer为输入参数类型
//String为返回值类型
public void printMoney(Function<Integer,String> moneyFormat) {
System.out.println("我的存款:" + moneyFormat.apply(this.money));
}
}
public class MyMoneyDemo {
public static void main(String[] args) {
Money me = new Money(99999999);
Function<Integer, String> moneyFormat = i -> new DecimalFormat("#,###")
.format(i);
// 函数接口链式操作
me.printMoney(moneyFormat.andThen(s -> "人民币 " + s));//函数表达式支持链式操作,在前面添加参数
}
}
- 其他相似函数
接口 | 输入参数 | 返回类型 | 说明 |
---|---|---|---|
Predicate | T | boolean | 断言 |
Consumer | T | / | 消费型接口 |
Function | T | R | 输入T输出R的函数 |
Supplier | / | T | 提供一个数据 |
UnaryOperator | T | T | 一元函数(输出输入类型相同) |
BiFunction<T,U,R> | T,U | R | 2个输入的函数 |
BinaryOperator | (T,T) | T | 2元函数(输出输入类型相同) |
public class FunctionDemo {
public static void main(String[] args) {
// 断言函数接口 IntPredicate自带类型的接口,有限选择使用
IntPredicate predicate = i -> i > 0;
System.out.println(predicate.test(-9));
//
// IntConsumer
// 消费函数接口
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("输入的数据");
}
}
5、lambda表达式的方法引用
采用的是::双冒号
class Dog {
private String name = "哮天犬";
/**
* 默认10斤狗粮
*/
private int food = 10;
public Dog() {
}
/**
* 带参数的构造函数
*
* @param name
*/
public Dog(String name) {
this.name = name;
}
/**
* 狗叫,静态方法
*
* @param dog
*/
public static void bark(Dog dog) {
System.out.println(dog + "叫了");
}
/**
* 吃狗粮 JDK
*
* 默认会把当前实例传入到非静态方法,参数名为this,位置是第一个;
*
* @param num
* @return 还剩下多少斤
*/
public int eat(int num) {//jdk默认会把当前实例传入this默认是第一个 ,但是静态方法没有 public int eat(Dog this,int num)
System.out.println("吃了" + num + "斤狗粮");
this.food -= num;
return this.food;
}
@Override
public String toString() {
return this.name;
}
}
public class MethodRefrenceDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(3);
// 方法引用
Consumer<String> consumer = System.out::println;
consumer.accept("接受的数据");
// 静态方法的方法引用
Consumer<Dog> consumer2 = Dog::bark;//使用类名加方法名
consumer2.accept(dog);
// 非静态方法,使用对象实例的方法引用
// Function<Integer, Integer> function = dog::eat;
//当输入和输出是一样的时候我们可以使用一元函数
// UnaryOperator<Integer> function = dog::eat;
//也可以使用指定类型接口
IntUnaryOperator function = dog::eat;
// dog置空,不影响下面的函数执行,因为java 参数是传值
dog = null;
System.out.println("还剩下" + function.applyAsInt(2) + "斤");
//
// // 使用类名来方法引用
// BiFunction<Dog, Integer, Integer> eatFunction = Dog::eat;
// System.out.println("还剩下" + eatFunction.apply(dog, 2) + "斤");
//
// // 构造函数的方法引用,没有输入只有输出的函数
// Supplier<Dog> supplier = Dog::new;
// System.out.println("创建了新对象:" + supplier.get());
//
// // 带参数的构造函数的方法引用
// Function<String, Dog> function2 = Dog::new;
// System.out.println("创建了新对象:" + function2.apply("旺财"));
// 测试java变量是传值还是穿引用
List<String> list = new ArrayList<>();
test(list);
System.err.println(list);
}
private static void test(List<String> list) {
list = null;
}
}
6、Lambda表达式的类型推断
@FunctionalInterface
interface IMath {
int add(int x, int y);
}
@FunctionalInterface
interface IMath2 {
int sub(int x, int y);
}
public class TypeDemo {
public static void main(String[] args) {
// 变量类型定义
IMath lambda = (x, y) -> x + y;
// 数组里
IMath[] lambdas = { (x, y) -> x + y };
// 强转
Object lambda2 = (IMath) (x, y) -> x + y;
// 通过返回类型
IMath createLambda = createLambda();
TypeDemo demo = new TypeDemo();
// 当有二义性的时候,使用强转对应的接口解决
demo.test( (IMath2)(x, y) -> x + y);
}
public void test(IMath math) {
}
public void test(IMath2 math) {
}
public static IMath createLambda() {
return (x, y) -> x + y;
}
}
7、Lambda表达式变量引用:
/**
* 变量引用
*/
public class VarDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Consumer<String> consumer = s -> System.out.println(s + list);
consumer.accept("1211");
}
}
8、Lambda级联表达式和柯里化
/**
* 级联表达式和柯里化
* 柯里化:把多个参数的函数转换为只有一个参数的函数
* 柯里化的目的:函数标准化
* 高阶函数:就是返回函数的函数
*/
public class CurryDemo {
public static void main(String[] args) {
// 实现了x+y的级联表达式
Function<Integer, Function<Integer, Integer>> fun = x -> y -> x
+ y;
System.out.println(fun.apply(2).apply(3));
Function<Integer, Function<Integer, Function<Integer, Integer>>> fun2 = x -> y -> z -> x
+ y + z;
System.out.println(fun2.apply(2).apply(3).apply(4));
int[] nums = { 2, 3, 4 };
Function f = fun2;
for (int i = 0; i < nums.length; i++) {
if (f instanceof Function) {
Object obj = f.apply(nums[i]);
if (obj instanceof Function) {
f = (Function) obj;
} else {
System.out.println("调用结束:结果为" + obj);
}
}
}
}
}