JavaSE-函数式接口、lambda表达式
函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
// 定义一个函数型接口,特点传入参数,调用一个方法
@FunctionalInterface
interface MathOperation {
int operation(int a, int b);
}
@FunctionalInterface
interface StrOperation {
void operation(String str);
}
四大函数型接口
-
Function
-
Supplier
-
Consumer
-
Predicate
Runnable(线程相关)
Function
(类型转换型函数接口)特点:有一个参数输入,有一个输出
import java.util.function.Function;
public class TestFunction {
public static void main(String[] args) {
// 传入T 类型数据,返回R 类型数据
/**
* 1. 使用匿名内部类方法实现函数型接口
* 2. 使用lambda 表达式实现函数型接口
*/
// 匿名内部类
Function<Integer, String> function = new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer.toString();
}
};
// lambda
Function<Integer, String> function2 = (Integer integer) -> {
return integer.toString();
};
System.out.println(function2.apply(1));
}
}
Predicate
(断定型函数接口)特点:输入一个类型的参数,返回一个boolean值
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class TestPredicate {
public static void main(String[] args) {
Predicate<Integer> predicate = new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
if (integer > 10)
return true;
else
return false;
}
};
Predicate<Integer> predicate2 = (i) -> i > 10;
System.out.println(predicate2.test(20));
List<Integer> integers = Arrays.asList(1, 5, 8, 9, 2, 10, 8);
// 断定型接口实现类
Predicate<Integer> p1 = (i) -> true; // 所有
Predicate<Integer> p2 = (i) -> i % 2 == 0; // 偶数
Predicate<Integer> p3 = (i) -> i % 2 == 1; // 奇数
Predicate<Integer> p4 = (i) -> i > 7; // 大于7
System.out.println("输出结果:");
for (Integer integer : integers) {
if (p4.test(integer)) {
System.out.print(integer + " ");
}
}
}
}
Consumer
(消费型函数接口)特点:传入一个参数没有返回值
import java.util.function.Consumer;
public class TestConsumer {
public static void main(String[] args) {
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer2 = (str)->{
System.out.println(str);
};
consumer2.accept("ok");
}
}
Supplier
(供给型函数接口)特点:没输入参数有返回值
import java.util.function.Supplier;
public class TestSupplier {
public static void main(String[] args) {
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "null";
}
};
Supplier<String> supplier2 = () -> {
return "null";
};
System.out.println(supplier2.get());
}
}
lambda 表达式
实现接口
public class Lambda {
public static void main(String[] args) {
Lambda lambda = new Lambda();
/**
* 定义函数接口的实现类:
* 1. 传统:定义一个实现类,重写接口类中的方法,new 实现类调用方法。
* 2. 使用lambda 表达式 (parameters) ->expression 或 (parameters) ->{ statements; } 来表示实现类
*/
MathOperation plus = (int a, int b) -> {
return a + b;
}; // 此处实际上就是重写了MathOperation接口类中的operation方法
System.out.println(lambda.operate(10, 5, plus));
StrOperation str_plus = (String str) -> {
System.out.println("hello +" + str);
}; // 此处实际上就是重写了StrOperation接口类中的operation方法
str_plus.operation("world");
}
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
// 定义一个函数型接口,特点调用函数返回数据
interface MathOperation {
int operation(int a, int b);
}
interface StrOperation {
void operation(String str);
}
}
作用域问题、使用说明
-
lambda 表达式只能引用标记了 final 的外层局部变量(默认使用final修饰),也就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
-
Lambda 表达式当中被引用的变量的值不可以被更改。
-
在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
-
和局部变量不同的是,Lambda内部对于成员变量以及静态变量是即可读又可写。
-
Lambda 表达式中使用 this 会引用创建该 Lambda 表达式的方法的 this 参数。
public class Lambda {
final static String string = "java";
public static void main(String[] args) {
final String STR = "javascript";
Lambda lambda = new Lambda();
/**
* 定义函数接口的实现类:
* 1. 传统:定义一个实现类,重写接口类中的方法,new 实现类调用方法。
* 2. 使用lambda 表达式 (parameters) ->expression 或 (parameters) ->{ statements; } 来表示实现类
*/
MathOperation plus = (int a, int b) -> {
return a + b;
}; // 此处实际上就是重写了MathOperation接口类中的operation方法
System.out.println(lambda.operate(10, 5, plus));
StrOperation str_plus = (String str) -> {
System.out.println("hello +" + str);
}; // 此处实际上就是重写了StrOperation接口类中的operation方法
str_plus.operation("world");
str_plus.operation(string);
str_plus.operation(STR);
}
private int operate(int a, int b, MathOperation mathOperation) {
return mathOperation.operation(a, b);
}
// 定义一个函数型接口,特点调用函数返回数据
interface MathOperation {
int operation(int a, int b);
}
interface StrOperation {
void operation(String str);
}
}
玩法
有参数无返回值函数式接口8种写法
@FunctionalInterface
public interface Fn{
void print(String str, String str1);
}
- 普通写法
Fn fn = new Fn(){
@Override
public void print(String str, String str1){
System.out.println(str+str1)
}
}
- lambda 表达式
Fn fn = (String str, String str1)->{
System.out.println(str+str1)
}
- lambda 表达式,参数类型可以省略
Fn fn = (str, str1)->{
System.out.println(str+str1)
}
- lambda 表达式,执行内容为一行时可以省略{}
Fn fn = (str, str1)->System.out.println(str+str1)
- lambda 表达式引用静态方法
public class Demo{
static Fn fn = (str, str1)->Demo2.print(str, str1);
public static void main(String[] args){}
public static class Demo2{
public static void print(String str, String str1){
System.out.println(str+str1)
}
}
}
- lambda 表达式使用::引用静态方法,隐藏参数;如果静态方法参数和函数式接口的方法参数一致,可以使用下面代码优化。
public class Demo{
static Fn fn = (str, str1)->Demo2.print(str, str1);
public static void main(String[] args){}
public static class Demo2{
public static void print(String str, String str1){
System.out.println(str+str1)
}
}
}
lambda 表达式优化
Fn fn = Demo2::print;
- lambda 表达式引用实例方法
public class Demo{
static Fn fn = (str, str1)->new Demo2().print(str, str1);
public static void main(String[] args){}
public static class Demo2{
public void print(String str, String str1){
System.out.println(str+str1)
}
}
}
- lambda 表达式使用::引用实例方法,隐藏参数;如果实例方法参数和函数式接口的方法参数一致,可以使用下面代码优化。
public class Demo{
static Fn fn = (str, str1)->new Demo2().print(str, str1);
public static void main(String[] args){}
public static class Demo2{
public void print(String str, String str1){
System.out.println(str+str1)
}
}
}
lambda 表达式优化
Fn fn = new Demo2()::print;
无参数有返回值函数式接口8种写法
class User {
private String name;
private int age;
private String sex;
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public User() {
}
public static class StaticMethod {
public static User user() {
return new User("chen", 20, "男");
}
}
public static class InstanceMethod {
public User user() {
return new User("li", 21, "男");
}
}
}
@FunctionalInterface
interface Fn {
User create_user();
}
public class Demo {
// 方式1:原始方法
Fn fn1 = new Fn() {
@Override
public User create_user() {
return new User("chen", 20, "男");
}
};
// 方式2:lambda 表达式
Fn fn2 = () -> {
return new User("chen", 20, "男");
};
// 方式3:lambda 表达式单行省略{},同时return 也可以省略
Fn fn3 = () -> new User("chen", 20, "男");
// 方式4:调用静态方法
Fn fn4 = () -> {
return User.StaticMethod.user();
};
// 方式5:调用静态方法,单行省略{},同时return 也可以省略
Fn fn5 = () -> User.StaticMethod.user();
// 方式6:使用:: 优化
Fn fn6 = User.StaticMethod::user;
// 方式7:调用实例方法
Fn fn7 = () -> {
return new User.InstanceMethod().user();
};
// 方式8:调用实例方法,单行省略{},同时return 也可以省略
Fn fn8 = () -> new User.InstanceMethod().user();
// 方式9:使用:: 优化
Fn fn9 = new User.InstanceMethod()::user;
// 方式10:调用空构造器,::优化
Fn fn10 = User::new;
/**
* 实际上是一下代码的优化
* Fn fn10 = new Fn(){
* @Override
* public User create_user(){
* return new User();
* }
* }
*/
}
有参数有返回值的函数值接口
class User {
private String name;
private int age;
private String sex;
public User(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public User() {
}
public static class StaticMethod {
public static User user(String name, int age, String sex) {
return new User(name, age, sex);
}
}
public static class InstanceMethod {
public User user(String name, int age, String sex) {
return new User(name, age, sex);
}
}
}
@FunctionalInterface
interface Fn {
User create_user(String name, int age, String sex);
}
public class Demo {
// 方式1:原始方法
Fn fn1 = new Fn() {
@Override
public User create_user(String name, int age, String sex) {
return new User(name, age, sex);
}
};
// 方式2:lambda 表达式
Fn fn2 = (String name, int age, String sex) -> {
return new User(name, age, sex);
};
// 方式3:lambda 表达式单行省略{},同时return 也可以省略,参数类型省略
Fn fn3 = (name, age, sex) -> new User(name, age, sex);
// 方式4:调用静态方法
Fn fn4 = (String name, int age, String sex) -> {
return User.StaticMethod.user(name, age, sex);
};
// 方式5:调用静态方法,单行省略{},同时return 也可以省略,参数类型省略
Fn fn5 = (name, age, sex) -> User.StaticMethod.user(name, age, sex);
// 方式6:使用:: 优化
Fn fn6 = User.StaticMethod::user;
// 方式7:调用实例方法
Fn fn7 = (String name, int age, String sex) -> {
return new User.InstanceMethod().user(name, age, sex);
};
// 方式8:调用实例方法,单行省略{},同时return 也可以省略,参数类型省略
Fn fn8 = (name, age, sex) -> new User.InstanceMethod().user(name, age, sex);
// 方式9:使用:: 优化
Fn fn9 = new User.InstanceMethod()::user;
// 方式10:调用空构造器,::优化
Fn fn10 = User::new;
/**
* 实际上是一下代码的优化
* Fn fn10 = new Fn(){
* @Override
* public User create_user(String name, int age, String sex){
* return new User(name, age, sex);
* }
* }
*/
}
特殊事例
public class Demo {
public static void main(String[] args) {
List<Integer> arrs = Arrays.asList(1, 5, 6, 9);
arrs.stream().forEach(System.out::println);
}
}
原因就是forEach中的参数是一个消费型的函数式接口,详细查看【函数是接口】-【Consumer】