时间:2023-01-03 08:30:07 | 栏目:JAVA代码 | 点击:次
Lambda是简洁的标识可传递匿名函数的一种方式。“互动”事件驱动下,最终面向对象编程和函数式编程结合才是趋势。 java中,一段代码的传递并不容易。因为JAVA是面向对象的语言,如果要传递一段代码,必须先构建类,再生成对应的对象来传递所要的代码。
在之前,JAVA的设计者都抗拒加入这一特性,虽然JAVA现有的特性也能通过类和对象实现类似的API但是这样复杂且不易于使用。在后期,问题早已不是JAVA是不是要变成一门使用函数式编程的语言,而是如何实现这种改变。
在java8之前已经有了多年的实验,然后JAVA8来了。
//1、单个参数 (String s)->s.length() //2、单个对象 (Apple a)->a.getWeight()>150 //3、多参数,多语句 (int a,int b)->{ System.out.println(a); System.out.println(b); } //4、空参数,返回int值42 ()->42 //5、多对象参数 (Applea1,Applea2)->a1.getWeight().compareTo(a2.getWeight())
Lambda表达式可以省略参数的类型,java编译器能自动推断
当lambda只有一个参数需要推断类型时,参数两边的括号可以省略
List<Apple> c=filter(inventory,a->"green".equals(a.getColor())); Comparator<Apple> c=(a1,a2)->a1.getWeight.compareTo(a2.getWeight());
JAVA8之前 内部类只允许访问final修饰的变量,现在使用lambda表达式,一个内部类可以访问任何有效的final局部变量-任何值不会发生变化的变量
对于已有的方法,如果希望作为lambda表达式来使用,可以直接使用方法引用
三种方法引用的情况
在第一种和第二种方法引用种,方法的引用等于提供方法参数的lambda表达式
例如:
对于第三种,则相当于第一个参数成为执行方法的对象
例如:String::compareToIngnoreCase 等同于(x,y) x.compareIngoreCase(Y);
对于构造器引用,相当于根据构造器的方法的参数,生成一个构造的对象的一个lambda表达式
例如:StringBuilder::new 可以表示为 (Stiring s)->new StringBuilder(s); 具体引用哪个构造器,编译器会根据上下文推断使用符合参数的构造器。
总结:就是只定义了一个抽象方法的接口,即使有一堆的default方法(default方法是为了增强某些API但避免现有大范围改动所有API所以推出了默认方法)
不同接口的默认方法冲突问题
如果实现的接口已有一个默认方法,但是另一个父类或者接口也有同样的默认方法。
其他:
接口中重写Object类的方法,例如 Comparator 一般是为了关联javadoc的注释。
介绍:函数式接口的抽象方法的签名,基本就是lambda表达式的签名,这种抽象方法称为 函数描述符
Predicate接口
方法签名为,输入某个对象 返回布尔结果
/** * java.util.Predicate 是一个只有test方法,返回布尔值的一个函数式接口, * 与其类似的还有用于比较,排序的Comparator接口,其只有一个返回整数的比较接口 * @param list * @param p * @param <T> * @return */ public static <T> List<T> filter(List<T> list, Predicate<T> p){ List<T> result=new ArrayList<>(); for (T t : list) { if (p.test(t)) result.add(t); } return result; } public static void main(String[] args) { //Predicate函数式接口示例 List<Apple> appleList=new ArrayList<>(); List<Apple> resulAppleList=filter(appleList,(Apple a)->a.getColor().equals("red")); }
Counsumer接口
Accept ()方法签名为,输入某个对象 返回void
/** * 常用2:Consume * consume接口定义了一个 名为accept的抽象方法,接收泛型 T 返回void * 可用来访问T类型的对象,并且执行某些操作。 * 如下用其创建,一个foreach方法,可以实现对所有List的遍历。且对每个对象执行consume定义的操作。 * 该foreach方法,java8之后成了List接口的default方法。 * @param list * @param <T> */ public static <T> void foreach(List<T> list, Consumer<T> consumer){ for (T t : list) { consumer.accept(t); } } //Consume函数式接口示例,遍历列表执行某项操作 foreach(appleList,(Apple a)->{if (a.getColor()==null);a.setColor("garly");}); appleList.forEach((Apple a)->{if (a.getColor()==null);a.setColor("garly");});
Function接口
Apply() 方法签名:输入某个对象、返回某个对象
/** * 常用2:Consume * consume接口定义了一个 名为accept的抽象方法,接收泛型 T 返回void * 可用来访问T类型的对象,并且执行某些操作。 * 如下用其创建,一个foreach方法,可以实现对所有List的遍历。且对每个对象执行consume定义的操作。 * 该foreach方法,java8之后成了List接口的default方法。 * @param list * @param <T> */ public static <T> void foreach(List<T> list, Consumer<T> consumer){ for (T t : list) { consumer.accept(t); } } //Consume函数式接口示例,遍历列表执行某项操作 foreach(appleList,(Apple a)->{if (a.getColor()==null);a.setColor("garly");}); appleList.forEach((Apple a)->{if (a.getColor()==null);a.setColor("garly");});
案例 | Lambda例子 | 对应的函数式接口 |
---|---|---|
布尔表达式 | (List list) ->list.isEmpty() | Predicate<List |
创建对象 | ()->new APPle() | Supplier |
消费一个对象 | (Apple a->{sout(a.getColor());} | Consumer |
从一个对象中提取 | (Apple a)>a.geWeight() | Function 或者其特殊化的 ToIntFunction |
合并两个值 | (int a,int b)->a+b | IntBinaryOperator |
比较两个对象 | (Apple a1,Apple a2)->a1.getWeight().compareTo(a2.getWeight()) | Comparator BigFunction<Apple,Apple,Integer> ToIntBigFunction<Apple,Apple> |
java的基本类型和引用类型之间,会自动的进行拆箱装箱,但是本质是吧原始类型包裹起来再保存在堆内存,所以装箱后需要更多内存。java位基本的类型定义了特有的函数式接口,一般只需要加上原始类型的前缀即可
输入基本类型的函数式接口:
DoublePredict
IntConsumer
LongBinaryOperate
输出基本类型的函数式接口:
ToIntFunction
List<Apple>apples=newArrayList<>(); apples.add(newApple("red",11)); apples.add(newApple("red",12)); apples.add(newApple("green",13)); /** *对排序lanmbda进行复复合-比较器链 *1、默认逆序方法:reversed() *2、多级比较:thenComparing() *example:对apples按照颜色排序后,进行逆序,如果颜色一样再按照重量递增 */ Comparator<Apple>comparator=Comparator.comparing(Apple::getColor).reversed().thenComparing(Apple::getWeight); apples.sort(comparator); /** *谓词复合且、或、非 *1、negate否定 *2、and且 *3、or或 *example:对不是红色的苹果进行过滤,且收集重量大于100的苹果 */ Predicate<Apple>redApplePredicate=a->a.getColor().equals("red"); Predicate<Apple>notRedApple=redApplePredicate.negate(); List<Apple>notRedAppleList=apples.stream().filter(notRedApple.and(apple->apple.getWeight()>100)).collect(Collectors.toList()); /** *函数复合 *1、andThen将前一lambda执行结果,作为后一表达式的参数 *2、compose将后一表达式的结果作为前一表达式的参数 *example;complexReult=g(f(x))例如g(f(1))step1:1+1=2step2:(1+1)*2+"" */ Function<Integer,Integer>f=x->x+1; Function<Integer,String>g=x->x*2+""; Function<Integer,String>complexResult1=f.andThen(g);