JDK1.8新特性(二): Lambda表达式 (参数列表) -> { } 和函数式接口@FunctionalInterface

Lambda表达式


二:简介

JDK的升级的目的有以下几个:增加新的功能、修复bug、性能优化、简化代码等几个方面,Lambda表达式就是属于简化代码,用于简化匿名实现类,提供一种更加简洁的写法。Lambda表达式在Swift语言中称之为代码块,Lambda表达式可以认为是一种特殊的接口,该接口必须只有一个抽象方法。

语法

(参数类型 参数名, 数参数类型 参数名2...) -> {
// code
};

小括号()中的内容就是方法中的参数列表包括参数类型、参数名,其中参数类型是可以省略的,当参数个数只有一个时也可以省略掉小括号;
花括号{}中的内容就是方法中的方法体,当方法体中只有一行代码时可以省略{},当方法体中只有一行代码并且需要返回值时也可以省略掉return;
由于Lambda表达式是匿名实现类的简写,是一种特殊的接口,当赋值给一个变量时也少不掉分号;

Lambda表达式的作用

  • 简化匿名实现类的书写
  • 作为函数中的参数来传递

二:示例

示例1:两个参数,一个返回值

IHello 一个很普通的接口,但接口中只能有一个抽象方法

public interface IHello {
String sayHello(String name, String msg);
}

Main

public class Main {
public static void main(String[] args) {
// 将一个Lambda表达式赋值给一个接口,说明Lambda表达式就是一种接口数据类型,只不过该接口只能有一个抽象方法
// 参数列表可以省略参数类型,可以写成(name, msg),
// 在JDK1.8中有个叫做类型推断的东西,可以自动推断出参数的类型,
// 因为IHello中只有一个抽象方法,知道方法了就知道参数列表了,从而就能推出参数类型来
IHello iHello = (String name, String msg) -> {
String hello = name + ": " + msg;
return hello;
};
// 调用接口的方法
String content = iHello.sayHello("mengday", "happy new year everyone!");
System.out.println(content);
}
}

示例2:一个参数,一个返回值

public interface IHello {
String sayHello(String name);
}

Main

public class Main {
public static void main(String[] args) {
// 参数列表可以省略参数类型,当只有一个参数时可以省略小括号 (String name) --> (name) --> name
// 当方法体中只有一行代码并且有返回值时可以同时省略花括号和return
// { return name + ": " + "happy new year everyone!";} --> name + ": " + "happy new year everyone!";
IHello iHello = name -> name + ": " + "happy new year everyone!";

String content = iHello.sayHello("mengday");
System.out.println(content);
}
}

示例3:没有参数,没有返回值

public interface IHello {
void sayHello();
}

main

public class Main {
public static void main(String[] args) {
// 当表达式没有参数时一对小括号是不能省略掉的
IHello iHello = () -> System.out.println("mengday: happy new year everyone!");
iHello.sayHello();
}
}

从这三个示例中我们发现我们只定义了接口,并没有定义实现类,而是通过Lambda表达式来代替了实现类。
注意:Lambda接口只能有一个抽象方法,可以同时拥有多个静态方法和默认方法。

示例4:Lambda表达式参数

public interface IHello { void sayHello(String name);
}
public class Main {

public static void sayHello(IHello iHello, String name) {
iHello.sayHello(name);
}

public static void main(String[] args) {

IHello iHello = name -> {
String content = name + ": " + "happy new year everyone!";
System.out.println(content);
};

// 这里可以把iHelo看成一个匿名实现类来传递参数
sayHello(iHello, "mengday");

// 如果去掉变量的接收,直接将Lambda表达式传递到参数中,此时Lambda表达式更像是一个函数
// 也就是说JDK1.8竟然可以将一个函数作为参数传递到方法中,这是之前版本做不到的
// 将函数作为方法的参数传递,一般用于回调函数,将回调函数传递到方法中
sayHello(name -> {
String content = name + ": " + "happy new year everyone!";
System.out.println(content);
}, "mengday");
}
}

示例5:集合排序示例

public static void main(String[] args) {

// 写法一:使用匿名内部类
// 好好学习,天天向上
List<String> words = Arrays.asList("good", "good", "study", "day", "day", "up");

// public static <T> void sort(List<T> list, Comparator<? super T> c)
Collections.sort(words, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
// 降续排序
return s2.compareTo(s1);
}
});

System.out.println(words);
// 写法二:使用Lambda表达式
// 咱俩谁跟谁
words = Arrays.asList("we", "two", "who", "and", "who");
Collections.sort(words, (String s1, String s2) -> {return s2.compareTo(s1);});
System.out.println(words);
// 写法三:使用Lambda表达式(简写)
// 有事起奏,无事退朝
words = Arrays.asList("if", "you", "have", "something", "to", "say", "then", "say!",
"if", "you", "have", "nothing", "to", "say", "go", "home!");
Collections.sort(words, (s1, s2) -> s2.compareTo(s1));
System.out.println(words);
}

函数式接口@FunctionalInterface

从我们自定义的IHello示例来看,Lambda表达式其实是一种接口类型的数据类型,严格的说Lambda表达式的数据类型是:函数式接口,是一种特殊的接口,该接口使用@FunctionalInterface注解来标记(不是必须的,可以不用该注解标记,IHello接口就没有使用该注解标记, ),并且接口中只能有一个抽象方法,可以有多个静态方法或者默认方法, 每一个该类型的lambda表达式都会被匹配到这个抽象方法。

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
// 其它static、default方法
}

@FunctionalInterface: 该注解没啥太大含义,该注解是给编译器做检查使用的,如果使用了该注解,编译器就会检查该接口中的抽象方法是不是只有一个,如果有多个就会报错:在接口Xxx中找到多个非覆盖抽象方法

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

我们完善一下我们的IHello, 使用@FunctionalInterface注解

@FunctionalInterface
public interface IHello {
void sayHello(String name);
}

我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,也就是说我们的IHello接口无论叫什么名字,接口中的方法无论叫什么名字都无所谓(只是可读性更好些),因此可以再进行抽象化一下,JDK1.8中提供了这样的函数式接口,我们也不需要再定义IHello接口了,JDK1.8中提供了Supplier、Consumer、Function、BiFunction,这几个是比较常用的

Supplier< T > 供应商:没有参数,有返回值

@FunctionalInterface
public interface Supplier<T> {
T get();
}

Consumer< T > 消费者: 只有一个参数,没有返回值

@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}

Function< T, R > 函数:一个参数,一个返回值

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}

BiFunction< T, U, R > 二元函数:两个参数,一个返回值

@FunctionalInterfacepublic interface BiFunction<T, U, R> {
R apply(T t, U u);
}

Comparator< T > 比较器:接收两个参数,返回比较的结果

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}

使用以上四大函数式接口来取代自定义的接口IHello

public class Main {
private static String end = ".";

public static void main(String[] args) {
// 直接使用JDK1.8提供的接口,不需要再定义IHello接口, 直接使用JDK提供的接口来接收Lambda表达式
Supplier<String> supplier = () -> "mengday: happy new year everyone!";
String result = supplier.get();
System.out.println(result);

Consumer<String> consumer = (name) -> System.out.println(name + ": " + "happy new year everyone!");
consumer.accept("mengday");

Function<String, String> func = (name) -> name + ": " + "happy new year everyone!";
String hi = func.apply("mengday");
System.out.println(hi);

// 在代码块的内部可以访问静态全局变量
// 在代码块中可以访问外边局部变量
// 在代码块的内部可以修改全局静态变量
// 在代码块内部是不能访问接口中的其它方法的
String split = ": ";
BiFunction<String, String, String> biFunction = (String name, String msg) -> {
end = "!";
String hello = name + split + msg + end;
return hello;
};
String hello = biFunction.apply("mengday", "happy new year everyone");
System.out.println(hello);

// 根据字符串长度比较大小
Comparator<String> comparator = (s1, s2) -> s1.length() - s2.length();
int compare = comparator.compare("abc", "ab");
System.out.println(compare);
}
}

Predicate< T > 断言 谓词: 用于测试一个条件的真假

package java.util.function;
import java.util.Objects;

@FunctionalInterface
public interface Predicate<T> {
// 在给定的参数上评估这个谓词
boolean test(T t);

// 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}

// 返回表示此谓词的逻辑否定的谓词,相当于not
default Predicate<T> negate() {
return (t) -> !test(t);
}

// 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}

// 返回根据 Objects.equals(Object, Object)测试两个参数是否相等的谓词
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object);
}
}

Main

public static void main(String[] args) {
// 可以构造复杂的条件: 并且and、或者or、否negate
String email = "[email protected]";
Predicate<String> predicate = (str) -> str.length() > 20;

// 测试 emial.length > 0 的boolean
boolean result = predicate.test(email); // false

// 测试 !(emial.length > 0) 的boolean
result = predicate.negate().test(email); // true

Predicate<String> orPredicate = (str) -> str.contains("@");
// 测试 emial.length > 0 or emial.contains("@")
result = predicate.or(orPredicate).test(email); // true
}

参考文章:

JDK1.8新特性(二): Lambda表达式 (参数列表) -> { } 和函数式接口@FunctionalInterface

原文地址:https://www.cnblogs.com/AlanWilliamWalker/p/11157374.html

时间: 2024-10-11 20:27:36

JDK1.8新特性(二): Lambda表达式 (参数列表) -> { } 和函数式接口@FunctionalInterface的相关文章

jdk1.8新特性之lambda表达式

lambda表达式其实就是指一个匿名函数,应用最广泛的就是匿名内部类.在jdk1.8之前,我们定义一个匿名内部类可能需要写一大坨代码,现在有了lambda之后,可以写的很简洁了.但不是说lambda只能用来简化匿名内部类,从lambda的实际作用和表现上来看,就是一个变量指代一个代码块.而能够使用lambda表达式的一个前提要求是,该变量必须实现某个函数式接口.啥是函数式接口?参考jdk1.8新特性之函数式接口.看例子: 1.函数式接口 * Copyright (c) 1994, 2013, O

jdk1.8新特性之lambda表达式及在Android Studio中的使用举例

Jdk1.8已经出很久了但是很多同学对它的特性在android studio 中的应用可能还不是很熟悉,今天我们就来对这个新特性在AS中做它的应用实践. 一.首先在有JDK1.8的情况下我们要在AS的设置中将这个地方设置成java1.8的. 二在build.gradle中添加上这两句 即: compileOptions {    sourceCompatibility 1.8    targetCompatibility 1.8} 这样就完成了使用之前的设置工作了.然后我们进入重要的应用. 那么

java8新特性之——lambda表达式的使用

lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升. Lambda表达式的语法(记得要在jdk1.8及以上的jdk环境下实验) Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->&

C++11 新特性之 Lambda表达式

lambda表达式可以用于创建并定义匿名的函数对象,以简化编程工作 Lambda的语法如下: [函数对象参数](操作符重载函数参数)->返回值类型{函数体} []内的参数指的是Lambda表达式可以取得的变量.(2)函数中的param就是指函数可以得到在Lambda表达式外的全局变量, 如果在[]中传入=的话,即是可以取得所有的外部变量,如(1)和(3)Lambda表达式 ()内的参数是每次调用函数时传入的参数. ->后加上的是Lambda表达式返回值的类型,如(3)中返回了一个int类型的变

C++11新特性(3) lambda表达式(1)

C++11添加了一项名为lambda表达式的新功能.通过这项功能能编写内嵌的匿名函数,而不必编写独立函数或函数对象,使得代码更加理解. lambda表达式包含以下部分. [capture_block](parameters) mutable exception_specification->return_type {body} 现在分析各个部分的内容: (capture_block)捕捉块:指定如何捕捉所在作用域的变量,并供给lambda主体部分使用. (parameter)参数(可选):lam

2020了你还不会Java8新特性?Lambda表达式及API(二)

lambda表达式 为什么要使用lambda表示式 在Java中无法将函数座位参数传递给一个方法,也无法返回一个函数的方法. 在js中,函数的参数是一个函数.返回值是另一个函数的情况是非常常见的.是一门经典的函数式语言. Java匿名内部类. 匿名内部类的介绍 Gradle的使用.可以完全使用maven的中央仓库. 进行安卓的开发时,gradle已经成为标配了. lambda: 匿名内部类 my_jButton.addActionListener(new ActionListener() { @

JDK8新特性02 Lambda表达式02_Lambda语法规则

//函数式接口:只有一个抽象方法的接口称为函数式接口. 可以使用注解 @FunctionalInterface 修饰 @FunctionalInterface public interface MyFun { public Integer getValue(Integer num); } import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List;

JDK8新特性01 Lambda表达式01_设计的由来

1.java bean public class Employee { private int id; private String name; private int age; private double salary; public Employee() { } public Employee(String name) { this.name = name; } public Employee(String name, int age) { this.name = name; this.a

好程序员分享java8新特性之Lambda表达式

?.Lambda表达式简介 什么是Lambda? Lambda表达式是Java 8推出的?个新特性.从本质上讲,Lambda表达式是?个匿名函数. 为什么要使?Lambda? 使?Lambda表达式可以对?个接?进??常简洁的实现. 之前我们在给?个接?引?赋值的时候,可以使?接?实现类,或者匿名内部类.但是有了 Lambda表达式,我们可以更加?便的实现这个需求. interface Comparator<T>?{ int compare(T o1, T o2); } class Progr