java中lambda的使用

lambda的使用

  • lambda表达式:
    • 思想转变:
      • 使用普通方法进行多线程操作
      • 使用匿名内部类
      • 使用lambda表达式
    • Lambda标准格式
    • Lambda的使用前提
    • 常用函数式接口
      • Supplier接口
      • Consumer接口
      • Predicate接口
      • Function接口

lambda表达式:

思想转变:

函数式编程思想:不在乎过程的方式,不在乎对象是那个,只在乎返回结果(重结果,轻过程)

面向对象思想:找一个对象,去做事情(万物皆对象)

转变过程:

以多线程为例:

使用普通方法进行多线程操作

为了获取Runnable接口的实现对象,为该接口定义一个实现类`RunnableImpl,设置线程任务

public class RunnableImpl implements Runnable {
	@Override
	public void run() {
		System.out.println("多线程任务执行!");
	}
}

然后创建该实现类的对象作为Thread类的构造参数:

public class Demo03ThreadInitParam {
	public static void main(String[] args) {
		Runnable task = new RunnableImpl();
		new Thread(task).start();
	}
}

使用匿名内部类

这个RunnableImpl类只是为了实现Runnable接口而存在的,而且仅被使用了唯一一次,所以使用匿名内部类的语法即可省去该类的单独定义,即匿名内部类:

public class Demo04ThreadNameless {
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("多线程任务执行!");
			}
		}).start();
	}
}

使用lambda表达式

public class Demo04ThreadNameless {
	public static void main(String[] args) {
		new Thread(() -> System.out.println("多线程任务执行!")).start();
	}
}

你会发现使用了lambda表达式的书写代码简约而不简单

Lambda标准格式

Lambda省去面向对象的条条框框,格式由3个部分组成:

  • 一些参数
  • 一个箭头
  • 一段代码

Lambda表达式的标准格式为:

(参数类型 参数名称) -> { 代码语句 }

格式说明:

  • 小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
  • ->是新引入的语法格式,代表指向动作。
  • 大括号内的语法与传统方法体要求基本一致。
  • lambda特点:延迟执行。

Lambda的使用前提

Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:

  1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法
    无论是JDK内置的RunnableComparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
  2. 使用Lambda必须具有上下文推断
    也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

备注:有且仅有一个抽象方法的接口,称为“函数式接口”。

@FunctionalInterface注解

与 @Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface 。该注
解可用于一个接口的定义上:

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

常用函数式接口

Supplier接口

java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。

作用:生产型接口,指定接口的泛型是什么,就生产什么类型的数据

Consumer接口

java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,
其数据类型由泛型决定。
抽象方法:accept
Consumer 接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。

作用:消费性接口,泛型执行什么类型,就可以使用accept消费什么类型的数据

默认方法:andThen
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作,
然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。下面是JDK的源代码:

Consummer con1;
Consummer con2;
String s="hello";
con1.accept(s);
con2.accept(s);
con1.andThen(con2).accept(s);

Predicate接口

作用:对某种类型的数据进行判断,从而得到一个boolean值结果。
java.util.function.Predicate 接口。
抽象方法:test
Predicate 接口中包含一个抽象方法: boolean test(T t) 。用于条件判断的场景:

默认方法:and ,有false则false
既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起来实
现“并且”的效果时,可以使用default方法 and 。

p1.and(p2).test(S)
p1.test(s)&&p2.test(s)

默认方法:or 有true则true
与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”。

默认方法:negate 有true则false,有false则true
“与”、“或”已经了解了,剩下的“非”(取反)也会简单。

Function接口

作用:接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。

java.util.function.Function
抽象方法:apply
Function 接口中最主要的抽象方法为: R apply(T t) ,根据类型T的参数获取类型R的结果。
使用的场景例如:将 String 类型转换为 Integer 类型。

默认方法:andThen
Function 接口中有一个默认的 andThen 方法,用来进行组合操作

你可能感兴趣的:(java面试题)