lambda
函数式编程只需要关注实现的功能,而不需要关注实现的细节
举例:
1 public class DemoMain { 2 3 /** 4 * 求最小值 5 * 6 */ 7 public static void main(String[] args) { 8 int[] nums = {33,23,34,89}; 9 10 int min = IntStream.of(nums).min().getAsInt(); 11 System.out.println(min); 12 13 14 } 15 }
创建线程
1 public class ThreadDemo { 2 3 public static void main(String[] args) { 4 new Thread(new Runnable() { 5 6 @Override 7 public void run() { 8 System.out.println("aaa"); 9 } 10 }).start(); 11 12 //jdk1.8 13 new Thread(()->System.out.println("aaa")).start(); 14 15 } 16 }
lamba表达式就是返回了一个实现指定接口的对象实例
jdk8 新增的接口默认方法
1 /**注为FunctionalInterface的接口被称为函数式接口,该接口只能有一个自定义方法,但是可以包括从object类继承而来的方法。如果一个接口只有一个方法,则编译器会认为这就是一个函数式接口 2 * (单一职责原则) 3 */ 4 @FunctionalInterface 5 interface inter { 6 int doubleNum(int i); 7 8 /** 9 * 新增接口默认方法 10 */ 11 default int add(int x,int y) { 12 return x+y; 13 } 14 } 15 16 17 @FunctionalInterface 18 interface inter2 { 19 int doubleNum(int i); 20 21 /** 22 * 新增接口默认方法 23 */ 24 default int add(int x,int y) { 25 return x+y; 26 } 27 } 28 29 30 @FunctionalInterface 31 interface inter3 extends inter,inter2 { 32 /** 33 * 指明重复的默认方法 34 */ 35 @Override 36 default int add(int x, int y) { 37 // TODO Auto-generated method stub 38 return inter2.super.add(x, y); 39 } 40 41 } 42 43 44 45 46 public class LambdaDemo { 47 48 49 public static void main(String[] args) { 50 51 inter i1 = (i) -> i*2; //1 52 53 System.out.println(i1.doubleNum(20)); 54 55 System.out.println(i1.add(10,20)); 56 57 inter i2 = i->i*2; //2 58 59 inter i3 = (int i)->i*2; //3 60 61 inter i4 = (int i)->{ 62 System.out.println("aaa"); 63 return i*2; 64 }; //4 67 } 68 69 }
函数接口
1 /** 2 * 函数接口好处 3 * 1.不用定义多的接口 4 * 2.支持链式的操作 5 * @author 11658 6 */ 7 8 9 /** 10 *定义输入类型int,输出类型String 11 */ 12 //interface IMoneyFormot{ 13 // String format(int i); 14 //} 15 16 17 class MyMoney{ 18 private final int money; 19 20 public MyMoney(int money) { 21 this.money = money; 22 } 23 24 public void printMoney(Function<Integer,String> iMoneyFormot) { 25 // System.out.println("我的存款:"+ iMoneyFormot.format(this.money)); 26 System.out.println("我的存款:"+ iMoneyFormot.apply(this.money)); 27 28 } 29 30 } 31 32 public class InterDemo { 33 34 public static void main(String[] args) { 35 36 37 MyMoney me = new MyMoney(1000); 38 39 Function<Integer, String> iMoneyFormot = i -> new DecimalFormat().format(i); 40 //链式操作 41 me.printMoney(iMoneyFormot.andThen(s->"$"+s)); 42 43 44 } 45 46 }
举例:
1 public class FunctionDemo { 2 3 public static void main(String[] args) { 4 //断言函数 5 //IntPredicate predicate = i -> i >0; 6 Predicate<Integer> predicate = i -> i >0; 7 System.out.println(predicate.test(-9)); 8 9 10 //消费函数接口 11 Consumer<String> consumer = s -> System.out.println(s); 12 consumer.accept("aaaa"); 13 14 } 15 }
方法引用
1.静态方法引用
2.使用对象实例方法引用
3.使用类名来引用
4.构造函数方法引用
1 class Dog{ 2 private String name = "金毛"; 3 4 private int food = 10; 5 6 public static void bark(Dog dog) { 7 System.out.println(dog+"在叫"); 8 } 9 10 /** 11 *吃狗粮 12 *输入 int 输出 int 13 */ 14 public int eat(int num) { 15 System.out.println("吃了"+num+"斤"); 16 this.food -= num; 17 return this.food; 18 } 19 20 21 @Override 22 public String toString() { 23 return this.name; 24 } 25 } 26 27 28 29 public class MethodDemo { 30 31 public static void main(String[] args) { 32 /** 33 * lambda表达式实际是匿名函数 34 * 函数左边是函数参数,右边是函数执行体 35 * 当函数执行体只有一个函数调用时,函数的参数和箭头左边一样,就可以缩写成方法引用的方式 36 */ 37 38 //Consumer<String> consumer = s->System.out.println(s); 39 40 Consumer<String> consumer = System.out::print; 41 42 consumer.accept("aaa"); 43 44 45 46 //1.静态方法的方法引用 47 //类名::静态方法名 48 Consumer<Dog> consumer2 = Dog::bark; 49 Dog dog = new Dog(); 50 51 consumer2.accept(dog); 52 53 //非静态方法引用 54 //2.使用对象实例方法引用 55 //实例::方法名 56 Function<Integer,Integer> function = dog::eat; 57 //方法的输入和输出类型一样,可改为一元函数接口 58 // UnaryOperator<Integer> function = dog::eat; 59 60 System.out.println("还剩"+function.apply(2)+"斤"); 61 62 } 63 }
aaa金毛在叫
吃了2斤
还剩8斤
1 class Cat{ 2 private String name = "小猫"; 3 4 private int food = 10; 5 6 /** 7 * 创建构造函数 8 */ 9 public Cat() { 10 11 } 12 13 //分析:输入String,输出当前类的实例 14 public Cat(String name) { 15 this.name = name; 16 } 17 18 /** 19 * eat 方法, 20 * jdk 默认会把当前实例传入到非静态方法,参数名是this,位置是第一个 21 * 用类名对非静态方法做引用的时候,实际上是有两个输入,一个输出 22 * 23 */ 24 public int eat(Cat this,int num) { 25 System.out.println("吃了"+num+"斤"); 26 this.food -= num; 27 return this.food; 28 } 29 30 31 @Override 32 public String toString() { 33 return this.name; 34 } 35 } 36 37 38 39 public class MethodDemo2 { 40 41 public static void main(String[] args) { 42 43 Cat cat = new Cat(); 44 cat.eat(2); 45 46 47 Function<Integer,Integer> function = cat::eat; 48 49 System.out.println("还剩"+function.apply(2)+"斤"); 50 51 //Cat::eat 52 //3.使用类名来引用方法 53 BiFunction<Cat,Integer,Integer> eatFunction = Cat::eat; 54 System.out.println("还剩"+eatFunction.apply(cat, 2)+"斤"); 55 56 57 //4.构造方法的引用 ,没有参数时,没有输入只有输出 58 //类名::new 59 Supplier<Cat> supplier = Cat::new; 60 System.out.println(supplier.get()); 61 62 63 64 /** 带参数的构造函数方法的引用 65 * 分析:输入String,输出当前类的实例 66 * public Cat(String name) { 67 * this.name = name; 68 } 69 */ 70 Function<String,Cat> function2 = Cat::new; 71 System.out.println(function2.apply("大橘")); 72 73 } 74 75 }
吃了2斤
还剩4斤
小猫
大橘
类型推断
1 /** 2 * 类型推断 3 * lambda表达式实际上是匿名函数,返回了一个指定接口的对象,究竟实现那个接口,否则就报错 4 * 这就是类型推断 5 */ 6 7 @FunctionalInterface 8 interface IMath{ 9 int add(int x,int y); 10 } 11 12 13 14 15 public class TypeDemo { 16 17 public static void main(String[] args) { 18 19 //变量类型定义 20 IMath math = (x,y) ->x+y; 21 22 //数组里 23 IMath[] math2 = {(x,y) -> x+y}; 24 25 //强转 26 Object math3 = (IMath)(x,y) -> x+y; 27 28 //通过返回类型 29 IMath createLambda = createLambda(); 30 31 TypeDemo demo = new TypeDemo(); 32 //指定方法 33 //当有二义性时,使用强转对应的接口解决 34 demo.test((x,y) -> x+y); 35 36 } 37 38 //通过方法指定接口,进行匹配 39 public void test(IMath math) {} 40 41 42 private static IMath createLambda() { 43 44 return (x,y) ->x+y; 45 46 } 47 48 }
变量引用
1 /** 2 * 变量引用 3 * @author 11658 4 * 5 */ 6 public class VarDemo { 7 8 public static void main(String[] args) { 9 /** 10 * 匿名类引用外部变量必须为final ? 保证里面的变量和外部的变量指向同一个对象 11 * 传参的形式是传值而不是传引用, 12 */ 13 final String str = "aaa"; 14 Consumer<String> consumer = s -> System.out.println(s+str); 15 16 consumer.accept("1222"); 17 } 18 19 }
1222aaa
级联表达式和柯里化
1 /** 2 * 级联表达式和柯里化 3 * 柯里化:把多个参数的函数转换为只有一个参数的函数 4 * 目的:函数标准化 5 */ 6 public class CurryDemo { 7 8 9 10 public static void main(String[] args) { 11 12 Function<Integer, Function<Integer,Integer>> fun= x -> y-> x+y; 13 14 System.out.println(fun.apply(2).apply(3)); 15 16 17 //函数标准化,进行统一处理 18 Function<Integer, Function<Integer,Function<Integer,Integer>>> fun2= x->y->z->x+y+z; 19 20 System.out.println(fun2.apply(2).apply(3).apply(4)); 21 22 23 } 24 25 26 27 }
完