目 录CONTENT

文章目录

函数式接口

半糖
2024-08-07 / 0 评论 / 0 点赞 / 31 阅读 / 16791 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-08-13,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

概念

  • 如果在接口中,只有一个抽象方法,那么这个接口就是函数式接口

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

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区