概念
如果在接口中,只有一个抽象方法,那么这个接口就是函数式接口
Lambda表达式使用的前提,就是接口必须是一个函数式接口
@FunctionalInterface
使用@FunctionalInterface注解来检查当前接口是否是一个函数式接口,如果不是函数式接口,则编译报错
方法引用
概念
对lambda表达式的扩展,在定义lambda表达式的内容时,如果这个内容之前已经定义过,那么就不需要再定义一遍,直接调用即可
格式
如果是一个构造方法:类名::new
如果是一个静态方法:类名::方法名
如果是一个非静态方法:对象名::方法名
作用
简化lambda表达式,提高了代码的可读性,使逻辑更加清晰
示例
创建实体类Person ,其中有构造方法、静态方法、非静态方法
public class Person {
private String name;
public Person() {
System.out.println("小宝贝你真好看");
}
//构造方法
public Person(String name) {
System.out.println(name + "你真好看!");
}
//静态方法
public static void show(String name) {
System.out.println(name + "你真好看!");
}
//非静态方法
public void show1(String name) {
System.out.println(name + "你真好看!");
}
}
使用方法引用
package functionalInterface;
import functionalInterface.sub.Person;
import org.junit.jupiter.api.Test;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 方法引用
*/
public class MethodReferenceClient {
@Test
public void test1() {
//引用构造
Consumer<String> con = Person::new;
con.accept("宝贝");
//可以引用无参构造,这里可以不返回返回值,因为构造方法无返回值
Supplier supplier = Person::new;
supplier.get();
//引用静态
Consumer<String> con1 = Person::show;
con1.accept("宝贝");
//引用非静态
Consumer<String> con2 = new Person()::show1;
con2.accept("宝贝");
}
}
常用内置函数式接口
消费型接口
Consumer<T><t>:消费型接口
void accept(T t):消费一个参数数据</t>
使用场景
该接口中的方法可以接收一个参数,接收的参数类型由泛型T指定,对参数的操作方式根据该接口的实现类决定,不需要返回值
常用方法
default Consumer andThen(Consumer<? super T> after):在调用者处理方式之后,再进行参数的处理方式的处理
注意
Consumer<T>的类型必须与参数类型保持一致
accept()前后可以编写代码,实现统一的处理方式
传入的lambda表达式是有参无返回
consumer可以当参数传递(调用方法default Consumer andThen(Consumer<? super T> after))
用法
定义消费型接口
这里也可以简化,不一定需要定义接口,直接定义方法也可以
package functionalInterface.sub;
import java.util.function.Consumer;
@FunctionalInterface
public interface ConsumerInterface {
/**
* @param str 传入的参数,只能有一个,需要多参数使用实体类包装
* @param con 消费型函数(consumer),使用lambda表达式(有参无返回)
*/
public void printNum(String str, Consumer<String> con);
}
package functionalInterface.sub;
import java.util.function.Consumer;
public class ConsumerInterfaceImpl implements ConsumerInterface{
public void printNum(String str, Consumer<String> con) {
// accept()前后可以编写代码,实现统一的处理方式
con.accept(str);
}
}
调用消费性接口
/**
* 调用消费型接口
*/
@Test
public void testComsumer() {
ConsumerInterface consumerInterface = new ConsumerInterfaceImpl();
// 多参数的话放入实体类中传递
System.out.println("1、-----------------直接调用方法并指定参数和lambda表达式------------------");
consumerInterface.printNum("aaa", System.out::println); //“System.out::println;等同于System.out.println(s)”,是简化版
System.out.println("2、----------------直接调用方法并指定参数和lambda表达式,参数传入lambda表达式可进行操作-------------------");
consumerInterface.printNum("aaa", s -> System.out.println(s.length()));
System.out.println("3、--- consumer1调用参数执行完后再consumer2调用参数执行---");
Consumer<String> consumer1 = System.out::println;
Consumer<String> consumer2 = s -> System.out.println(s.length());
consumer1.andThen(consumer2).accept("consumerInterfaceParam");
}
供给型接口
Supplier<T><t>:供给型接口
T get(): 该方法不需要参数,它会按照某种逻辑,返回一个具体的数据
使用场景
该方法不需要参数,它会按照某种逻辑,返回一个具体的数据,返回数据的类型由泛型T决定
注意
该接口也被称为生产型接口,如果指定了泛型是什么类型,那么get()就返回该类型的具体数据。
返回的数据,由该接口的泛型决定。
传入的lambda表达式是无参有返回,多返回使用实体类封装
用法
定义供给型接口
package functionalInterface.sub;
import java.util.ArrayList;
import java.util.function.Supplier;
@FunctionalInterface
public interface SupplierInterface {
/**
* @param sup 供给型函数(supplier),使用lambda表达式(无参有返回)
* @return 返回类型由实现类决定,返回类型的泛型由Supplier<T>的泛型决定
*/
public ArrayList<Integer> getList(Supplier<Integer> sup);
}
package functionalInterface.sub;
import java.util.ArrayList;
import java.util.Random;
import java.util.function.Supplier;
public class SupplierInterfaceImpl implements SupplierInterface {
@Override
public ArrayList<Integer> getList(Supplier<Integer> sup) { //Supplier<T>的泛型决定返回类型的泛型
// 实现类进行一系列操作
Random r = new Random();
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(sup.get()); //sup.get()返回的数据类型为Supplier<Integer>的泛型
}
return list; //实现类决定返回ArrayList类型的list
}
}
调用接口
@Test
public void testSupplier() {
SupplierInterface supplierInterface = new SupplierInterfaceImpl();
System.out.println("------调用方法并指定lambda表达式(无参表达式有返回,这里是简化模式)------");
//向集合中添加5个1-100之间的随机数并输出
System.out.println(supplierInterface.getList(() -> new Random().nextInt(100) + 1));
//向集合中添加5个1-20之间的随机数并输出
System.out.println(supplierInterface.getList(() -> new Random().nextInt(20) + 1));
}
spring security源码示例
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.core.context;
import java.util.function.Supplier;
import org.springframework.util.Assert;
/**
* A <code>ThreadLocal</code>-based implementation of
* {@link SecurityContextHolderStrategy}.
*
* @author Ben Alex
* @author Rob Winch
* @see java.lang.ThreadLocal
* @see org.springframework.security.core.context.web.SecurityContextPersistenceFilter
*/
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final ThreadLocal<Supplier<SecurityContext>> contextHolder = new ThreadLocal<>(); <1>
@Override
public void clearContext() {
contextHolder.remove();
}
@Override
public SecurityContext getContext() {
return getDeferredContext().get();
}
@Override
public Supplier<SecurityContext> getDeferredContext() {
Supplier<SecurityContext> result = contextHolder.get();
if (result == null) {
SecurityContext context = createEmptyContext();
result = () -> context; <2>
contextHolder.set(result);
}
return result;
}
@Override
public void setContext(SecurityContext context) {
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
contextHolder.set(() -> context); <3>
}
@Override
public void setDeferredContext(Supplier<SecurityContext> deferredContext) {
Assert.notNull(deferredContext, "Only non-null Supplier instances are permitted");
Supplier<SecurityContext> notNullDeferredContext = () -> {
SecurityContext result = deferredContext.get();
Assert.notNull(result, "A Supplier<SecurityContext> returned null and is not allowed.");
return result;
}; <4>
contextHolder.set(notNullDeferredContext);
}
@Override
public SecurityContext createEmptyContext() {
return new SecurityContextImpl();
}
}
这个一个使用线程策略储存安全上下文的实体类,其中contextHolder 的泛型就是供给型接口。
<1>处定义了个ThreadLocal,泛型使用的是供给型接口,接口泛型是SecurityContext,contextHolder的get()返回的是Supplier<SecurityContext>(不懂看ThreadLocal源码),Supplier<SecurityContext>的get()返回的是SecurityContext(接口定义的)
<2>、<3>、<4>处使用lambda表达式构建了一个匿名供给型函数并赋值给对应的Supplier<SecurityContext>引用,最后set进contextHolder,实现上下文的存储
函数型接口
Function<T,R><t, r="">:函数型接口
R apply(T):接收一个数据,操作数据之后,返回一个新的数据
使用场景
接收一个参数,参数的类型根据泛型T指定,然后通过该接口的实现类对象对该数据进行操作,操作之后返回一个泛型为R的新数据
常用方法
default Function andThen(Function f):先通过调用者对象处理参数,将处理的结果再通过f对象处理,将两个处理的结果进行返回
注意
lambda表达式是有参有返回,多参数使用实体类封装,多返回也是
接收和返回的数据类型都由Function<T,R>的T和R决定
用法
定义函数型接口
package functionalInterface.sub;
import java.util.function.Function;
@FunctionalInterface
public interface FunctionInterface {
/**
*
* @param s 参数类型由Function<T,R>的T决定
* @param fun 函数型函数(function),使用lambda表达式(有参有返回)
* @return r 返回值类型由Function<T,R>的R决定
*/
public int strInt(String s, Function<String, Integer> fun);
}
package functionalInterface.sub;
import java.util.function.Function;
public class FunctionInterfaceImpl implements FunctionInterface{
@Override
public int strInt(String s, Function<String, Integer> fun) {
//实现类进行一系列操作
return fun.apply(s);
}
}
调用接口
@Test
public void testFunction() {
FunctionInterface functionInterface = new FunctionInterfaceImpl();
/*
* 使用该方法时
* 第一点先传递该方法的参数1 【需要处理的数据】
* 第二点要传递该数据的处理方式 【如何处理】
*/
System.out.println(functionInterface.strInt("aaa", s -> s.length()));
System.out.println(functionInterface.strInt("123", s -> Integer.parseInt(s)));
System.out.println("----------------------------------------------------");
//将 function1 和 function2 两种方式结合到一起,形成新的function3
Function<String, String> function1 = s -> "hello" + s;
Function<String, Integer> function2 = s -> s.length();
Function<String, Integer> function3 = function1.andThen(function2);
/*
* 接收参数,之后,先使用function1的方式处理,然后在使用function2的方式处理,最终处理结果是返回值
* 将 abc 参数先通过 function1 方式处理,返回值 helloabc。然后交给function2 方式处理 返回个数:8
*/
System.out.println(function3.apply("abc"));
}
断言型接口
Predicate<t>:断言型接口
boolean test(T t) :对数据做出指定的判断
使用场景
接收一个指定泛型的参数,并根据该接口的实现类 对象对该参数做出对应的判断,返回只为boolean类型
常用方法
Predicate and(Predicate p):先将参数通过调用者判断真假,再将参数通过p判断真假,全真 为真,否则为假
Predicate or(Predicate p):全假为假,否则为真
Predicate negate():取反
注意
lambda表达式有参有返回,多参数使用实体类封装,返回boolean类型的值
用法
定义断言型接口
package functionalInterface.sub;
import java.util.ArrayList;
import java.util.function.Predicate;
@FunctionalInterface
public interface PredicateInterface {
/**
* @param list 传入的参数
* @param pre 断言型函数(predicate),使用lambda表达式(有参有返回,多参数使用实体类封装,返回boolean类型的值)
* @return r 返回值必定是bloolean类型
*/
public boolean is(ArrayList<String> list, Predicate<String> pre);
}
package functionalInterface.sub;
import java.util.ArrayList;
import java.util.function.Predicate;
public class PredicateInterfaceImpl implements PredicateInterface{
@Override
public boolean is(ArrayList<String> list, Predicate<String> pre) {
//实现类进行一系列操作
for (String s : list) {
if (!pre.test(s)) {
return false;
}
}
return true;
}
}
调用接口
@Test
public void testPredicate() {
PredicateInterface predicateInterface = new PredicateInterfaceImpl();
//构造一个需要传递的参数
ArrayList<String> st = new ArrayList<>();
st.add("aac");
st.add("bbc");
st.add("ccc");
/*
* 在使用该方法时,不仅需要给出需要处理的参数,也要给出判断条件
* 一旦条件给定之后,将来判断的结果就会随着条件的不同而改变
*/
System.out.println(predicateInterface.is(st, s -> s.startsWith("a")));
System.out.println(predicateInterface.is(st, s -> s.length() == 2));
System.out.println("--------------------------------------------");
/*
* 使用and、or、negate连接方法进行叠加判断
*/
Predicate<Integer> pre1 = s -> s >= 10 && s <= 100;
Predicate<Integer> pre2 = s -> s >= 20 && s <= 80;
//连接两个判断方式:全真为真,否则为假 ------ &
System.out.println(pre1.and(pre2).test(21));
//连接两个判断方式:全假为假,否则为真 ------ |
System.out.println(pre1.or(pre2).test(11));
//对某个结果取反
System.out.println(pre1.negate().test(12));
}
评论区