Java 函数式编程(常用接口)

news2024/11/27 18:43:42

        之前已经介绍过了Java8函数式变成及Lambda表达式,感兴趣可以看看,地址:Java8函数式编程(Lambda表达式)_琅琊之榜PJ的博客-CSDN博客

 本文主要介绍一下常用的接口及用法,先来看一个表格:

 本文主要选取几个常用的:Supplier<T>、Consumer<T>、Function<T,R>、Predicate<T>

在此之前,再来了解一下@FunctionalInterface注解。

一、@FunctionalInterface注解

        一种信息注释类型,用于指示接口类型声明是Java语言规范定义的函数接口。从概念上讲,函数接口只有一个抽象方法。由于默认方法有一个实现,所以它们不是抽象的。如果一个接口声明了一个覆盖java.lang.Object的一个公共方法的抽象方法,那么这也不计入该接口的抽象方法计数,因为该接口的任何实现都将具有来自java.lang.Oobject或其他地方的实现。

        注意,函数接口的实例可以使用lambda表达式、方法引用或构造函数引用创建。

        如果使用此注解类型对类进行注解,则编译器需要生成错误消息,除非类型是接口类型,而不是注解类型、枚举或类。

        带注解的类型满足功能接口的要求。

        但是,无论接口声明中是否存在FunctionalInterface注释,编译器都会将符合函数接口定义的任何接口视为函数接口。

源码如下:

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

需要注意的是:函数式接口只有一个抽象方法,接口声明覆盖 java.lang.Object的抽象方法,不会进行抽象方法计数。这对后面介绍几个常用的接口很有用!!

二、Supplier<T>

        先看一下源码:

/**
  * 表示结果的供应者。
  * 没有要求每次调用供应者时都返回新的或不同的结果。
  */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     */
    T get();
}

        Supplier<T> 接口源码中只有个get()方法。每次调用get()方法,就会调用构造方法,获取对象实例。

        示例:每次调用get()方法都返回一个整数:

        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return new Random().nextInt();
            }
        };
        System.out.println(supplier.get());

        结合Lambda表达式应用:

    List<Integer> integers = makeList(10, () -> (int) (Math.random() * 10));
    integers.forEach(System.out::println);
 
    private List<Integer> makeList(int num, Supplier<Integer> supplier){
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(supplier.get());
        }
        return list;
    }

        结合方法引用应用:

Supplier<Double> supplier1 = Math::random;
System.out.println(supplier1.get());

三、Consumer<T>

Java源码:

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

        Consumer<T>表示接受单个输入参数而不返回结果的操作。java.util.function.Consumer 接口则正好与上面的Supplier<T> 接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定。

该类有两个方法

  • void accept(T t);【抽象方法】

        该方法对给定的参数执行此操作。

  • default Consumer<T> andThen(Consumer<? super T> after)【默认实现方法】

        返回一个组合的Consumer,该Consumer依次执行此操作和after操作。如果执行任何一个操作都会引发异常,则会将异常中继到组合操作的调用方。如果执行此操作会引发异常,则不会执行after操作。

1、抽象方法accept的使用

该方法消费一个指定泛型的数据:

import java.util.function.Consumer;
 
public class Demo01Consumer {
    public static void main(String[] args) {
        consumerString(s -> System.out.println(s));
    }
 
    private static void consumerString(Consumer<String> function) {
        function.accept("Hello");
    }
}

运行程序,控制台输出:Hello

2、默认方法andThen的使用

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

default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

提示:java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出 NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。

        要想实现组合,需要两个或多个Lambda表达式即可,而 andThen 的语义正是“一步接一步”操作。例如两个步骤组合的情况:

import java.util.function.Consumer;
 
public class Demo02Consumer {
    public static void main(String[] args) {
        consumerString(
                // toUpperCase()方法,将字符串转换为大写
                s -> System.out.println(s.toUpperCase()),
                // toLowerCase()方法,将字符串转换为小写
                s -> System.out.println(s.toLowerCase())
        );
    }
 
    private static void consumerString(Consumer<String> one, Consumer<String> two) {
        one.andThen(two).accept("Hello");
    }
}

        运行结果将会首先打印完全大写的HELLO,然后打印完全小写的hello。当然,通过链式写法可以实现更多步骤的组合。

四、Function<T,R>

源码如下:

@FunctionalInterface
public interface Function<T, R> {


    R apply(T t);


    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }


    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

Function<T,R>接口的作用的是用来表现一个参数类型为T、返回值类型为R的函数(方法)。

Function 接口是一个功能型接口,是一个转换数据的作用。接收一个T参数,返回一个R结果

Function 接口实现 apply 方法来做转换。

一个简单的示例:

Function<String, Boolean> function = p -> p.length() == 5;
Stream<Boolean> stream = stringList().stream().map(function);

默认方法1:<V> Function<V, R> compose(Function<? super V, ? extends T> before)

返回一个组合函数,该函数首先将before函数应用于其输入,然后将此函数应用于结果。如果对任意一个函数的求值引发异常,则会将异常中继到组合函数的调用方。

默认方法2:<V> Function<T, V> andThen(Function<? super R, ? extends V> after)

返回一个组合函数,该函数首先将此函数应用于其输入,然后将after函数应用于结果。如果对任意一个函数的求值引发异常,则会将异常中继到组合函数的调用方。

静态方法:static <T> Function<T, T> identity()

返回一个始终返回其输入参数的函数。

五、Predicate<T>

源码:

@FunctionalInterface
public interface Predicate<T> {


    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

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


    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Predicate<T>常用的四个方法:
boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非
default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与
default Predicate<T> or(Predicate other):返回一个组合判断,对应短路或
Predicate<T>接口常用于判断参数是否满足指定的条件

最常见的应用是在集合Stream流过滤条件中使用:

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
 
 
public class LambdaStudy
{
    public static void main(String[] args) {
       
        //初始化list集合
        List<String> list = new ArrayList<String>();
        list.add("测试数据1");
        list.add("测试数据2");
        list.add("测试数据3");
        list.add("测试数据12");
        
        //使用λ表达式遍历集合
        list.forEach(s -> System.out.println(s));
        
        //结合Predicate使用和过滤条件筛选元素
        Predicate<String> contain1 = n -> n.contains("1");
        Predicate<String> contain2 = n -> n.contains("2");
        
        //根据条件遍历集合
        list.stream().filter(contain1).forEach(n -> System.out.println(n));
        list.stream().filter(s -> contain1.test(s)).forEach(s -> System.out.println(s));
        list.stream().filter(contain1.and(contain2)).forEach(n -> System.out.println(n));
        list.stream().filter(contain1.or(contain2)).forEach(n -> System.out.println(n));
        
        //将过滤后的元素重新放到一个集合中
        List<String> newList = list.stream().filter(contain1.and(contain2)).collect(Collectors.toList());
        
        newList.forEach(s -> System.out.println(s));
 
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/753118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

强引用、软引用、弱引用和虚引用的区别

主要的区别在于什么时候回收对象&#xff1b; 强引用&#xff1a;垃圾回收器就不会回收这个对象&#xff1b;软引用&#xff1a;如果内存足够&#xff0c;不回收&#xff0c;如果内存不足&#xff0c;则回收&#xff1b;弱引用&#xff1a;不管当前内存空间足够与否&#xff0…

Jupyter notebook添加与删除kernel

目录 1 添加虚拟环境的kernel 2 删除jupyter notebook已有的kernal 3 切换内核与查看当前内核 4 添加C语言的kernel 5 添加python2的kernel 6 添加java语言的kernel 6.1 sudo apt install default-jre 6.2 下载并安装 ijava 6.3 sudo apt install openjdk-11…

四、评估已建立的模型

别人不讲道理 不是我们跟着不讲道理的理由 1 模型评估 希望fθ(x)对未知数据x输出的预测值尽可能正确。 如何测量预测函数fθ(x)的正确性&#xff0c;也就是精度呢&#xff1f; 观察函数的图形&#xff0c;看它能否很好地拟合训练数据&#xff1a; 我们需要能够定量地表示机…

2022 JavaScript调查:TypeScript持续主导,Vite和Tauri大受欢迎

StateOfJS 最新发布了 2022 年 JavaScript 现状调查报告指出&#xff0c;Solid 和 Qwik 等新兴前端框架正在挑战 React 的权威。该报告基于对近 40,000 名 Web 开发人员的调查&#xff0c;数量几乎是去年的两倍。 JavaScript 可能发展得很快&#xff0c;但 JavaScript 开发人员…

4. Shuffle 5. 内存的管理

4. Shuffle (1) Shuffle 的原理和执行过程 在Scala中&#xff0c;Shuffle是指对集合或序列进行随机打乱或重新排列的操作。它可以用于打乱集合中元素的顺序&#xff0c;以便在后续的操作中获得更好的随机性或均匀性。 在Scala中&#xff0c;可以使用scala.util.Random类的shu…

只会Excel制表?搭配上这个工具,让你的办公效率无限翻倍

在每次考试之后&#xff0c;老师们通常需要进行繁重的工作&#xff0c;包括使用Excel汇总学生的考试成绩、计算平均分和成绩排名等。然而&#xff0c;现在学校不允许公布学生成绩&#xff0c;这给老师们增加了额外的工作量和麻烦。一些老师采取了将学生成绩表截成一条一条的成绩…

使用HummerRisk进行K8s安全合规检测

1.简介 HummerRisk 是开源的云原生安全平台&#xff0c;以非侵入的方式解决云原生的安全和治理问题。核心能力包括混合云的安全治理和云原生安全检测。 今天我们来通过 HummerRisk 云原生安全检测能力来对Kubernetes进行安全合规检测 2.检测步骤 ①首先创建一个Kubernetes账…

spring复习:(19)单例bean是在哪里被加入到一级缓存的?

AbstractBeanFactory的doGetBean方法&#xff1a; 如果是第一次调用getBean时&#xff0c;会执行到下边的代码&#xff1a; getSingleton的代码如下&#xff1a; public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(bea…

windows安装mysql8.0.23版本成功示例-免安装

windows安装mysql8.0.23版本成功示例 一.通过mysql-installer-*.msi安装包的方式1.安装准备1.1 官网下载地址1.2 选择合适的版本点击下载 2.安装mysql 二.通过mysql-8.0.23-winx64.zip压缩包免安装方式1.安装准备1.1 下载官网压缩包1.2 解压后配置文件my.ini信息1.3 配置my.ini…

共筑开源新长城 龙蜥社区走进开放原子校源行-清华大学站

6 月 28 日&#xff0c;以“聚缘于校&#xff0c;开源共行”为主题的 2023 年开放原子校源行活动在清华大学成功举行。本次活动由开放原子开源基金会和清华大学共同主办&#xff0c;来自各行业的 22 位大咖共聚校园共话开源。龙蜥社区技术专家边子政受邀进行技术分享&#xff0…

安达发|如何选择性价比高的APS软件?

生产计划和调度决不是越精确越好。理论上&#xff0c;APS可以调度每一分钟&#xff0c;可以调度每一个人&#xff0c;每一台设备的每一个动作。这只对自动化生产线有意义。 我国企业管理水平参差不齐。许多工业企业可能不像一百年前的泰勒时代那样管理得那么好。对于一些工业企…

搭载率突破40%!智能数字座舱比拼,车企还有降本空间吗?

进入2023年&#xff0c;汽车行业的「降本」风潮&#xff0c;驱动产业链上下游开始思考智能化、电动化的投入产出。除了显性的硬件成本&#xff08;继续堆料&#xff0c;强调性价比&#xff0c;还是减配&#xff09;&#xff0c;软件及背后的开发成本&#xff0c;对于车企来说&a…

C++STL:关联容器之map和multimap

文章目录 1. map概述成员函数创建C map容器的几种方法迭代器map获取键对应值的几种方法map insert()插入数据的4种方式map emplace()和emplace_hint()方法 2. multimap概述成员函数创建C multimap容器的方法 1. map 概述 作为关联式容器的一种&#xff0c;map 容器存储的都是…

自研组件-createIntersectionObserver实现图片懒加载组件

项目&#xff1a;taro3vue3 描述&#xff1a;图片懒加载通过滚动距离的计算进行加载&#xff0c;这里记录下用createIntersectionObserver来实现 createIntersectionObserver介绍任意门 原理比较简单&#xff0c;通过监听图片&#xff0c;出现在显示区域内就渲染图片&#xf…

Qt Creator常用快捷键及技巧

1.[Qt Creator常用快捷键及技巧提升编码效率] (https://blog.csdn.net/luoyayun361/article/details/105431913) 介绍了一些小技巧比如: 自动补全函数快捷注释函数前输入/** 回车自动补全注释alt 整列进行编写或者 左右移动,非常有用某一行的复制 ctrlaltup (或者down)向上向…

远程CentOs安装了MySQL,本地的Nvaicat/SqlYog无法正常连接?

#1、创建新用户 mysql> CREATE USER ‘username’‘%’ IDENTIFIED BY ‘userpassword’; #给普通用户远程连接的权限&#xff1a; #2、授权 myuser 用户对指定库的所有表&#xff0c;所有权限并设置远程访问 mysql> GRANT ALL ON 指定库.* TO ‘username’‘%’; #3、更…

查看域名的ip地址

1."winr" -- ping www.baidu.com 2."nslookup www.baidu.com"

点云数据标注方法研究

1.点云可视化工具 1.1 cloudcompare下载安装 sudo snap install cloudcompare 启动方法: #open pointcloud viewer cloudcompare.ccViewer #open the main software cloudcompare.CloudCompare 使用上述第一条命令&#xff0c;读取的点云某一帧数据&#xff0c;我的点云格…

作为帮助文档使用,语雀和Baklib哪个更适合?

语雀和Baklib都是常见的在线文档协作工具&#xff0c;它们都提供了方便的文档编辑、协作和分享功能。然而&#xff0c;它们在一些方面存在差异&#xff0c;这取决于你的具体需求和使用场景。 下面将对语雀和Baklib进行综合比较: 1. 功能和编辑体验 语雀和Baklib都具有强大的…

Golang学习之结构体和内存对齐、map设计思路

Golang学习之结构体和内存对齐、map设计思路 结构体和内存对齐内存对齐如何确定一个结构体的对其边界 map设计思路哈希表与扩容bmap的结构练习map扩容规则 结构体和内存对齐 cpu要想从内存读取数据&#xff0c;需要通过地址总线&#xff0c;把地址传输给内存&#xff0c;内存准…