java8中的lambda表达式,看这篇绝对够

目录
  • Lambda表达式
  • 特性
  • 一、lambda表达式介绍
    • 1.1 lambda表达式结构
    • 1.2 常见的Lambda表达式
    • 1.3 基本语法
    • 1.4 类型检查
    • 1.5 类型推断
    • 1.6 变量作用域
    • 1.7 方法引用
    • 1.8 构造器引用
  • 二、在何处使用lambda表达式
    • 2.1 函数式接口介绍
    • 2.2 常见的函数式接口
    • 2.3 常见的Lambda和已有的实现
    • 2.4 针对装箱拆箱的优化
    • 2.5 复合Lambda函数

Lambda表达式

Lambda是简洁的标识可传递匿名函数的一种方式。“互动”事件驱动下,最终面向对象编程和函数式编程结合才是趋势。 java中,一段代码的传递并不容易。因为JAVA是面向对象的语言,如果要传递一段代码,必须先构建类,再生成对应的对象来传递所要的代码。

在之前,JAVA的设计者都抗拒加入这一特性,虽然JAVA现有的特性也能通过类和对象实现类似的API但是这样复杂且不易于使用。在后期,问题早已不是JAVA是不是要变成一门使用函数式编程的语言,而是如何实现这种改变。

在java8之前已经有了多年的实验,然后JAVA8来了。

特性

  • 匿名:lambda表达式不像面向对象的方法一样,有确定的名称。
  • 函数:虽然lambda不是对象的方法,属于某个特定的类。但是lambda表达式一样的有参数列表、函数主体 返回类型和异常声明
  • 传递:lambda表达式可以作为参数传递
  • 简洁:无需像匿名类一样有固定模板的代码,lambda写得少而想得多
  • JAVA8中 可以为接口增加静态方法、可以为类增加默认方法

一、lambda表达式介绍

1.1 lambda表达式结构

1.2 常见的Lambda表达式

//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())

1.3 基本语法

  • (参数…)-> 表达式 隐式返回表达式结果
  • (参数…)->{执行语句} 可用return语句 显示返回执行结果
  • 函数式接口不允许抛出受检异常
  • 注意:当参数只有一个时,也可以去掉参数的括号。原因是java编译器的自动类型推断

1.4 类型检查

  • Lambda的类型由上下文推断而来
  • 同样的lambda表达式,不同的函数式接口,只要方法的签名一致,同样的表达式可以用于不同的函数是接口。
  • 只有函数式接口的实现,能承载lambda表达式
  • Objecto=()-{System.out.print("HellowWorld")}这是不合法的 因为Object不是一个函数式接口

1.5 类型推断

Lambda表达式可以省略参数的类型,java编译器能自动推断

当lambda只有一个参数需要推断类型时,参数两边的括号可以省略

List<Apple> c=filter(inventory,a->"green".equals(a.getColor()));
Comparator<Apple> c=(a1,a2)->a1.getWeight.compareTo(a2.getWeight());

1.6 变量作用域

JAVA8之前 内部类只允许访问final修饰的变量,现在使用lambda表达式,一个内部类可以访问任何有效的final局部变量-任何值不会发生变化的变量

  • java限制了 lambda表达式访问的自由变量,值是不可更改的,因为这会导致出现无法预料的并发问题。
  • java编译器的限制是有限的,只对局部变量有效,如果使用静态变量,或者示例变量,编译器不会提示任何错误。这样仍然是不安全的。
  • 可以用数组 int[] counter =new int[1]; button.setOnAaction(event->counter[0]++); 任然可以让lambda对局部变量进行重新赋值。
  • lambda表达式的方法体,与被嵌套的代码块具有同样的作用域,所有适用同样的命名冲突和变量屏蔽规则。

1.7 方法引用

对于已有的方法,如果希望作为lambda表达式来使用,可以直接使用方法引用

三种方法引用的情况

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法

在第一种和第二种方法引用种,方法的引用等于提供方法参数的lambda表达式

例如:

  • System.out::println() 等同于 System.out.print(x)
  • Math::pow 等同于 (x,y)->Math.pow(x,y)

对于第三种,则相当于第一个参数成为执行方法的对象

例如:String::compareToIngnoreCase 等同于(x,y) x.compareIngoreCase(Y);

1.8 构造器引用

对于构造器引用,相当于根据构造器的方法的参数,生成一个构造的对象的一个lambda表达式

例如:StringBuilder::new 可以表示为 (Stiring s)->new StringBuilder(s); 具体引用哪个构造器,编译器会根据上下文推断使用符合参数的构造器。

二、在何处使用lambda表达式

2.1 函数式接口介绍

总结:就是只定义了一个抽象方法的接口,即使有一堆的default方法(default方法是为了增强某些API但避免现有大范围改动所有API所以推出了默认方法)

不同接口的默认方法冲突问题

如果实现的接口已有一个默认方法,但是另一个父类或者接口也有同样的默认方法。

  • 如果是父类和接口默认方法一致,那么直接使用父类的方法实现,忽略接口中的默认方法(类优先规则,如果尝试重写默认方法toString 那么永远都不会优于Object的toString)
  • 如果一个父接口提供了一个默认方法,另一个接口也提供了同名称和参数的方法(不论是否默认方法)那么都必须覆盖改方法。

其他:

接口中重写Object类的方法,例如 Comparator 一般是为了关联javadoc的注释。

2.2 常见的函数式接口

介绍:函数式接口的抽象方法的签名,基本就是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");});

2.3 常见的Lambda和已有的实现

案例 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>

2.4 针对装箱拆箱的优化

java的基本类型和引用类型之间,会自动的进行拆箱装箱,但是本质是吧原始类型包裹起来再保存在堆内存,所以装箱后需要更多内存。java位基本的类型定义了特有的函数式接口,一般只需要加上原始类型的前缀即可

输入基本类型的函数式接口:

  • DoublePredict
  • IntConsumer
  • LongBinaryOperate

输出基本类型的函数式接口:

  • ToIntFunction

2.5 复合Lambda函数

	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);

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • JAVALambda表达式与函数式接口详解

    Lambda表达式的诞生是为了解决JAVA创建匿名内部类代码冗余的问题.例子如下: public class Lambda { public static void main(String[] args) { Gog gog = new Gog() { @Override public void say() { System.out.println("WOW"); } }; gog.say(); } } interface Gog { void say(); } 这里我们想实现接口的s

  • Java Lambda表达式常用的函数式接口

    失去人性,失去很多:失去兽性,失去一切.——<三体> 在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口.它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例. Supplier接口 Supplier接口是对象实例的提供者,定义了一个名叫get的抽象方法,它没有任何入参,并返回一个泛型T对象,具体源码如下: package java.util.function; @Functio

  • 深入浅出理解Java Lambda表达式之四大核心函数式的用法与范例

    目录 1.四大核心函数式接口 1.1 Consumer<T> : 消费型接口 1.2 Supplier<T> : 供给型接口 1.3 Function<T, R> : 函数型接口 1.4 Predicate<T> : 断言型接口 2.方法引用 2.1 对象 :: 实例方法 2.2 类 :: 静态方法 2.3 类 :: 实例方法 3.构造器引用 4.数组引用 1.四大核心函数式接口 上一篇文章中说到了Lambda表达式中的基本语法,以及我们如何自定义函数式接口

  • Java 进阶使用 Lambda 表达式实现超强的排序功能

    目录 基于Comparator排序 使用 Lambda 表达式替换Comparator匿名内部类 通过静态方法抽取公共的 Lambda 表达式 借助Comparator的comparing方法 多条件排序 在Stream中进行排序 倒序排列 调转排序判断 在Comparator.comparing中定义排序反转 在Stream中定义排序反转 null 值的判断 元素是 null 的笨拙实现 排序条件的字段是 null 文末总结 我们在系统开发过程中,对数据排序是很常见的场景.一般来说,我们可以采

  • Java中常用的Lambda表达式案例解析

    目录 1.ForEach 2.Collect 3.Filter 4.Map 5.MapToInt 6.Distinct 7.Sorted 8.groupingBy 9.FindFirst 10.Reduce 11.Peek 12.Limit 13.Max,Min 总结 前言: 我们日常工作中,Lambda 使用比较多的场景,就是集合类下的 Lambda 流操作,往往几行代码可以帮助我们实现复杂代码 接下来我们把 Lambda 流的常用方法用案列讲解一下. 1.ForEach 集合的遍历forEa

  • Java中Lambda表达式用法介绍

    Lambda lambda是一个匿名函数,我们可以把lambda表达式理解为是一段可以传递的代码. lambda简明的地将代码或方法作为参数传递进去执行. "函数式编程"其核心是把函数作为值. 函数式接口 :只有一个 抽象方法的接口 称之为 函数式接口.函数式接口可以使用@FunctionalInterface进行注解. lambda表达式拆分为两部分 左侧:lambda 表达式的参数列表 右侧:lambda 表达式中所需要执行的功能,即lambda体 语法格式一:无参数,无返回值 @

  • 关于Java 中的 Lambda 表达式

    这篇文章我们将讨论关于Java 中的 Lambda 表达式,Lambda 表达式是 Java 涉足函数式编程的过程.它接受参数并将其应用于表达式或代码块.以下是语法的基本示例: (parameter1, parameter2) => expression 或者 (parameter1, parameter2) => {code block} Lambda 表达式非常有限,如果它不是 void,则必须立即返回一个值.他们不能使用诸如 if 或 for 之类的关键字来保持简单性.如果需要更多行代码

  • Java Lambda表达式超详细介绍

    目录 一.背景 1.Lambda表达式的语法 2.函数式接口 二.Lambda表达式的基本使用 三.语法精简 四.变量捕获 五.Lambda在集合当中的使用 1.Collection接口 六.List接口 1.sort()方法的演示 七.Map接口 一.背景 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块). L

  • java8中的lambda表达式,看这篇绝对够

    目录 Lambda表达式 特性 一.lambda表达式介绍 1.1 lambda表达式结构 1.2 常见的Lambda表达式 1.3 基本语法 1.4 类型检查 1.5 类型推断 1.6 变量作用域 1.7 方法引用 1.8 构造器引用 二.在何处使用lambda表达式 2.1 函数式接口介绍 2.2 常见的函数式接口 2.3 常见的Lambda和已有的实现 2.4 针对装箱拆箱的优化 2.5 复合Lambda函数 Lambda表达式 Lambda是简洁的标识可传递匿名函数的一种方式.“互动”事

  • Java8中的 Lambda表达式教程

     1. 什么是λ表达式 λ表达式本质上是一个匿名方法.让我们来看下面这个例子: public int add(int x, int y) { return x + y; } 转成λ表达式后是这个样子: (int x, int y) -> x + y; 参数类型也可以省略,Java编译器会根据上下文推断出来: (x, y) -> x + y; //返回两数之和 或者 (x, y) -> { return x + y; } //显式指明返回值 可见λ表达式有三部分组成:参数列表,箭头(-&g

  • 详解Java8中的lambda表达式、::符号和Optional类

    Java8中的lambda表达式.::符号和Optional类 0. 函数式编程 函数式编程(Functional Programming)属于编程范式(Programming Paradigm)中的用语,此外还有命令式编程(Imperative Programing)等,有兴趣的同学可以自行了解,我们这里大概解释一下函数式编程,在函数式编程中,输入一旦确定了,输出都确定了,函数调用的结果只依赖于传入的输入变量和内部逻辑,不依赖于外部,这样的写出的函数没有副作用.举个例子: public cla

  • Java8中的lambda表达式入门教程

    1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public String getName() { ret

  • 详解Java8中的Lambda表达式

    Lambda是什么 Lambda表达式,也可称为闭包,是java8的新特性,作用是取代大部分内部类,优化java代码结构,让代码变得更加简洁紧凑. Lambda的基本语法 (expression)->expression 或 (expression)->{statements;} Lambda最重要特点 用()->{}代码块替代匿名内部类 //(param)->expression;//(param)->statment;//(param)->{statments};/

  • java8中的lambda表达式简介

    目录 Lambda表达式的语法 Lambda表达式作用域 方法引用 指向静态方法的方法引用 指向任意类型实例方法的方法引用 指向现有对象的实例方法的方法引用 构造方法引用 lambda与匿名内部类 匿名内部类 总结 Lambda表达式类似匿名函数,简单地说,它是没有声明的方法,也即没有访问修饰符.返回值声明和方法名. Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中). Lambda表达式的语法 (parameters) -> expression 或 (parameters)

  • Java8与Scala中的Lambda表达式深入讲解

    前言 最近几年Lambda表达式风靡于编程界.很多现代编程语言都把它作为函数式编程的基本组成部分.基于JVM的编程语言如Scala.Groovy及Clojure把它作为关键部分集成在语言中.而如今,(最终)Java 8也加入了这个有趣的行列. Java8 终于要支持Lambda表达式!自2009年以来Lambda表达式已经在Lambda项目中被支持.在那时候,Lambda表达式仍被称为Java闭包.在我们进入一些代码示例以前,先来解释下为什么Lambda表达式在Java程序员中广受欢迎. 1.为

  • 详解Java8如何使用Lambda表达式进行比较

    目录 支持Lambda的基本排序 无类型定义的基本排序 使用引用静态方法进行排序 Sort Extracted Comparators 反向排序 使用多个条件进行排序 使用多个条件排序-组合 使用Stream.sorted()对列表进行排序 使用Stream.sorted()对列表进行反向排序 Null值 结论 在Java 8之前,对集合进行排序需要为排序中使用的比较器 Comparator 创建一个匿名内部类: new Comparator<Human>() { @Override publ

  • Java8 新特性Lambda表达式实例详解

    Java8 新特性Lambda表达式实例详解 在介绍Lambda表达式之前,我们先来看只有单个方法的Interface(通常我们称之为回调接口): public interface OnClickListener { void onClick(View v); } 我们是这样使用它的: button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { v.setText("

  • C++中的Lambda表达式详解

    我是搞C++的 一直都在提醒自己,我是搞C++的:但是当C++11出来这么长时间了,我却没有跟着队伍走,发现很对不起自己的身份,也还好,发现自己也有段时间没有写C++代码了.今天看到了C++中的Lambda表达式,虽然用过C#的,但是C++的,一直没有用,也不知道怎么用,就可怜的连Lambda语法都看不懂.好了,这里就对C++中的Lambda进行一个简单的总结,就算是对自己的一个交代,我是搞C++的,我是一个C++ programmer. 一段简单的Code 我也不是文艺的人,对于Lambda的

随机推荐