Java函数式编程基础之【Optional类】详解

一、概述

Optional 是 Java 8 引入的新特性,它是一种特殊的包装类,里面只存储一个元素(这一点与基本数据类型的包装类有点相似)。有的文档称其为容器类,但它不同于 Conllection框架中的集合类,它一个容器只能存储一个元素。

Optional是Java中的一个类,它的作用是用于解决空指针异常的问题,它提供了一些有用的方法,可以帮助我们避免显式进行空值检测。

Java中的Optional类,可以包装类型T的值,这是一个可以为null的容器对象。Java 8 引入Optional替代以前版本中的空值(null),可以避免空指针异常(NullPointerException)问题,表示一个值可能存在也可能不存在。
Optional 可表示一个非空或空的Optional对象。如果一个Optional实例是非空的,表示它保存有一个类型为T的值;如果Optional实例为空(null),则类型T的值不存在。

Optional提供很多有用的方法,以避免显式地进行空值检测。
如果值存在,那么方法isPresent()会返回true,调用get()方法会返回该对象;
如果值不存在,那么方法isPresent()会返回false,调用get()方法会产生空指针异常(NullPointerException, 简称 NPE)。

Optional类主要用于方法返回类型,以明确表示方法可能返回空值。
Optional 类专用于防止空指针异常(NullPointerException, 简称 NPE)的问题。
Optional 类提供了一种优雅的方式来处理可能为空的值,避免显式进行空值检测,防止空指针异常的产生。通过合理使用 Optional,可以使代码更加简洁、可读性更高。

Optional类的缺点是引入额外的对象的开销。在有些情形不正确使用它,会影响系统性能。

Optional类的特性:

  1. 非空性:Optional类总是包含一个值或者为空。
  2. 不可变性:Optional对象一旦创建,就不可更改。
  3. 链式操作:可以连续调用多个方法,如map、filter等。

二、Optional 类的属性和构造器的定义及创建实例方法:

Optional 类位于 java.util 包中,Optional的属性和构造器部分定义的源代码如下:

public final class Optional<T> {
	//两个属性
	private static final Optional<?> EMPTY = new Optional<>();//空容器
	private final T value; //value 存储容器内唯一元素
	
	//两个构造器
	private Optional() {  //无参构造方法
        	this.value = null;
    }

    private Optional(T value) { //有参构造方法(value不允许为空)
        	this.value = Objects.requireNonNull(value);
    }
}

Optional 类的两个构造器都是私有的,不能直接用构造器创建Optional 类的实例。
创建Optional 类的实例需要使用静态方法,下面是Optional 类创建实例的三个静态方法:
三个静态方法的定义的源码:

	//创建值为'null'的Optional 类实例(空容器)的静态方法
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
	//创建Optional 类实例(value不允许为空)的静态方法
	public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
	//创建Optional 类实例(value允许为空)的静态方法
	public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

第三个创建实例的静态方法,实际上是前面二个静态方法的组合应用。

创建实例的示例:

	//创建空的 Optional 实例
	Optional<String> emptyOpt = Optional.empty();
	//创建非空的 Optional 实例
	Optional<String> opt = Optional.of("中国");
	//创建可以为空的 Optional 实例
	Optional<String> nullableOpt = Optional.ofNullable(null);

注意事项:
两个创建Optional实例的静态方法:of() 和 ofNullable() 方法的区别:如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException:

        //如此创建Optional<User>,可能是null时,of() 方法会抛出 NullPointerException
        Optional<User> optUser = Optional.of(null);

因此,你应该明确对象不为 null 的时候才可使用 of()方法。
如果对象即可能是 null 也可能是非 null,你就应该使用 ofNullable() 方法:

        //如此创建Optional<User>,可能是null时,可使用ofNullable()方法
        Optional<User> optUser = Optional.ofNullable(null);

三、Optional 类的常用方法:

  • Optional 类的四个获取(访问) Optional 对象所包含值的方法(get、orElse、orElseGet和orElseThrow):
    T get(): 如果调用对象包含值,返回该值,否则抛异常
    T orElse(T other) :如果值存在则将其返回,否则返回指定的other对象。
    T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
    T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则返回该值,否则是空值则抛出由Supplier接口实现提供的异常。

四个获取调用对象所包含值的方法的源码:

	//获取容器中唯一元素
	public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
    //获取容器唯一元素,若为空,返回指定值
    public T orElse(T other) {
        return value != null ? value : other;
    }
    //获取容器唯一元素,若为空,返回供应者(Supplier)提供的元素
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
//如果非空值则返回该值;否则抛出由Supplier接口提供的异常。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

说明:
从 Optional 实例中取回实际值对象的方法
方法get() :如果调用对象包含值,返回该值,否则抛异常。要避免异常,你首先要判断Optional容器中是否有值,然后再取;
方法orElse(T other):需要指定空值时返回的类型为T的一个默认值;
方法orElseGet(Supplier<? extends T> other):则需要指定一个供应者,供应一个类型为T的值。
方法orElseThrow(Supplier<? extends X> exceptionSupplier) :则需要指定一个供应者,供应一个异常。
Optional 应用示例一:

	Optional<String> opt = Optional.of("江山如画!");
	if (opt.isPresent()) {
		System.out.println(opt.get());
	}
	//注意下面二个方法的不同之处	
	Optional<User> op = Optional.ofNullable(null);
	User user1 = op.orElse(new User("张三", 20));
	User user = op.orElseGet(() -> new User("张三", 20));
	
	Optional<User> userOpt = Optional.ofNullable(null);
	User user = userOpt.orElse(new User("王五",32));
	userOpt.orElseThrow(() -> new NullPointerException());

我们修改一下上面的代码,来说明一个性能问题:

	//注意下面二个方法的不同之处	
	Optional<User> op2 = Optional.ofNullable(new User("李四", 20));
	User user1 = op2.orElse(new User("张三", 20));
	User user = op2.orElseGet(() -> new User("张三", 20));

这个示例中,op2是非空值,最终结果两个 Optional 对象都包含相同的非空值(两个方法也都会返回对应的非空值)。看上去两种方式好像是等价的,但是,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不会创建 User 对象。
在执行较密集的调用的情形,例如频繁地调用 Web 服务或数据查询,这个差异会对性能产生重大影响。因此,在实际应用中,还是要权衡利弊选择合适的方法。

  • Optional实例值是否为空(值是否存在)的两个判别方法
    boolean isPresent() : 判断调用对象的值是否存在。
    void ifPresent(Consumer<? super T> consumer) :测试调用对象的值是否存在。如果有值存在,就把该值作为参数传给Consumer接口,并执行Consumer接口的实现代码。
    二个判别方法的源码:
    public boolean isPresent() {
        return value != null;
    }

    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

Optional 应用示例二:

		//isPresent() 判断是否存在非空的值
		Optional<String> opt = Optional.of("江山如画!");
		if (opt.isPresent()) {
			System.out.println(opt.get());
		}
		
		//ifPresent() 检查是否有值存在
		opt.ifPresent(System.out::println);
		
		User user = new User(6, "测试用户");
        Optional<User> userOpt = Optional.ofNullable(user);
        userOpt.ifPresent(u->u.setName("新用户"));
        System.out.println(user);
  • Optional筛选元素的过滤器方法filter()
    如果 Optional 中的值满足测试条件,返回这个 Optional,否则返回一个空的 Optional。
    过滤器方法filter()源码:
	    public Optional<T> filter(Predicate<? super T> predicate) {
        	Objects.requireNonNull(predicate);
        	if (!isPresent())
            	return this;
        	else
            	return predicate.test(value) ? this : empty();
    	}

Optional 应用示例三:

	Optional<String> longOpt = opt.filter(s -> s.length() > 3);

	Optional<User> op = Optional.of(new User("张三", 20));
	Optional<User> op2 = op.filter(user -> user.age > 18);
  • Optional的映射器方法map()、flatMap()与链式调用
    先来学习一下,映射器方法map()和flatMap()的源码:
	//map()源码
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
	//flatMap()源码
    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }

提示:
映射器方法map()和flatMap()的方法签名如下所示:

	Optional<U> map(Function<? super T, ? extends U> mapper)
	Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

这两个映射器方法返回的流(Stream)元素的值都包装在 Optional 中。这就使得对返回值进行链试调用的操作成为可能。
map方法: 对Optional中的值进行转换(若值为空,则map方法什么也不做,直接返回空的Optional对象)。
这个变换基于提供该map的函数,并且这个变换是可选的,如果optional的值为空则不会做任何改变,并且map方法不会改变原始的Optional对象,而返回新的Optional对象,因此可以链式调用进行多个转换操作。
flatMap()方法: 用于扁平化嵌套的Optional结构,以避免引入不必要的嵌套层级。flatmap的映射转换函数返回的必须也是一个Optional对象;flatMap()方法可以用于嵌套的Optional情况,可以将两个互为嵌套关系的Optional对象转换为一个Optional对象。如果原始的Optional对象为空,或转换函数返回的Optional对象为空,那么最终得到的也是空的Optional对象。
两者区别: 若只需要对Optional对象中的值进行转换,而不需要处理嵌套的Optional,那么使用map方法更合适。
如果要对Optional对象进行一些操作返回另外一个Optional对象,flatmap方法更合适。

Optional 应用示例四:
如果 Optional 对象是非空值,则映射后返回一个新的 Optional对象,否则返回空的Optional对象。

	//假如names是文件名的数组
    Optional<FileInputStream> fis =
         names.stream().filter(name -> !isProcessedYet(name))
                       .findFirst()
                       .map(name -> new FileInputStream(name));

Optional 应用示例五:处理链式调用
当处理多个可能为空的值时,可以使用链式调用来避免嵌套的 if 判断。

	Optional<String> result = Optional.ofNullable(person)
    	.map(Person::getAddress)
    	.map(Address::getStreet);

综合实例:

package stream.Optional;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class OptionalExample {
    public static void main(String[] args) {
        // 创建 Optional 对象
        Optional<String> emptyOpt = Optional.empty();
        Optional<String> opt = Optional.of("江山如画!");
        Optional<String> nullableOpt = Optional.ofNullable(null);

        // 检查 Optional 对象
        if (opt.isPresent()) {
            System.out.println(opt.get());
        }
        opt.ifPresent(System.out::println);

        // 使用 orElse
        String value1 = opt.orElse("默认值");
        System.out.println(value1);

        // 使用 orElseGet
        String value2 = opt.orElseGet(() -> "供应一个默认值");
        System.out.println(value2);

        // 使用 orElseThrow
        try {
            String value3 = emptyOpt.orElseThrow(() -> new IllegalArgumentException("值缺失"));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        // 使用 map
        Optional<String> upperOpt = opt.map(String::toUpperCase);
        upperOpt.ifPresent(System.out::println);

        // 使用 flatMap
        Optional<Integer> lengthOpt = opt.flatMap(s -> Optional.of(s.length()));
        lengthOpt.ifPresent(System.out::println);

        // 使用 filter
        Optional<String> longOpt = opt.filter(s -> s.length() > 3);
        longOpt.ifPresent(System.out::println);

        // 结合 Optional 和流
        List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
        Optional<String> nameOpt = names.stream()
            .filter(name -> name.startsWith("J"))
            .findFirst();
        nameOpt.ifPresent(System.out::println);

        // 在实践中使用 Optional
        Optional<String> configValue = Optional.ofNullable(getConfig("key"));
        configValue.ifPresent(System.out::println);

        Optional<User> userOpt = Optional.ofNullable(findUserById(1));
        userOpt.ifPresent(System.out::println);

        Optional<String> paramOpt = Optional.ofNullable(getRequestParam("param"));
        paramOpt.ifPresent(System.out::println);
    }

    private static String getConfig(String key) {
        // 模拟配置项获取
        return "value";
    }

    private static User findUserById(int id) {
        // 模拟数据库查询
        return new User(id, "John Doe");
    }

    private static String getRequestParam(String param) {
        // 模拟 HTTP 请求参数获取
        return "paramValue";
    }
}

class User {
    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public void setName(String name) {
		this.name = name;
	}
 
    @Override
    public String toString() {
        return "User{ID号=" + id + ", 姓名='" + name + '\'' + '}';
    }
}

四、如何使用Optional?

在使用Optional的时候需要考虑一些事情,以决定什么时候如何使用?
Optional不支持 Serializable。因此,在需要序列化进行网络传输和存储的场景中,它不宜用作为类的属性字段。

Optional主要用作方法的返回类型。 在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。
Optional类有一个非常有用的场景,就是将其与流(Stream)或其它返回 Optional 的方法结合,以构建流畅的函数式编程的流管道。
我们来看一个示例,使用Stream的函数式编程中使用返回Optional对象的 findFirst() 方法:

    List<User> users = new ArrayList<>();
    User user = users.stream().findFirst().orElse(new User(15,"默认用户"));

Optional的应用场景:

    1. 方法返回多个结果:当一个方法需要返回多个结果,但其中某些结果可能不存在时。
    1. 处理链式调用:在链式调用中,某些操作可能返回null,使用Optional可以避免空指针异常。
    1. 集合操作:在处理集合时,特别是在需要对集合进行转换或过滤的场合,Optional可以提供更加清晰的逻辑。
    1. 函数式接口:与Function、Predicate等函数式接口结合使用,可以构建更加灵活的数据处理链。

五、借助Optional 类的函数式编程风格的链式调用的应用实例

Optional 是 Java 函数式编程的基础之一,它可帮助在函数式编程在流式的范式中实现。但是 Optional的意义显然不止于此。
当处理多层嵌套的对象时,使用 Optional 可以避免深层次的 null 检查,使代码更加简洁。
我们从一个简单的使用实例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 空指针异常(NullPointerException):

	String isocode = user.getAddress().getCountry().getPostcode().toUpperCase();

上面这行演示代码实现从一个用户(User)中获取邮政编码(postcode)的功能。如果我们需要确保不触发空指针异常,就得在访问每一个值之前对其进行明确的检查:

//普通的面向对象风格的版本
User user = new User(6, "测试用户","315040");
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String postcode = country.getPostcode();
            if (postcode != null) {
                postcode = postcode.toUpperCase();
            }
        }
    }
}

你看到了这个代码是没有Optional时的写法,代码变得冗长,难以阅读,也难以维护。
我们来看看傲使用Optional类如何简明实现这个功能。
从创建和验证实例,到调用其不同的方法,并与其它返回相同类型的方法相结合,下面是见证 Optional奇迹的时刻。
首先,需要重构User类,使其 getter 方法返回 Optional 实例:

	public class User {
    	private Address address;
		    
		public User(int id, String name, String postcode) {
        	this.id = id;
       		this.name = name;
        	this.postcode = postcode;
    	}
    	public Optional<Address> getAddress() {
        	return Optional.ofNullable(address);
    	}

    	// ...
	}
	
	public class Address {
    	private Country country;

    	public Optional<Country> getCountry() {
        	return Optional.ofNullable(country);
    	}

    	// ...
	}

	public class Country {
    	private Postcode postcode;
    
    	public Optional<Postcode> getPostcode() {
        	return Optional.ofNullable(postcode);
    	}

    	// ...	
	}

上面的User类定义相关的嵌套结构,可以用下面的示意图来表示:
在这里插入图片描述
最终,我们把“普通的面向对象风格的版本”转换为“函数式编程风格的版本”,如下:

	//函数式编程风格的版本
	User user = new User(6, "测试用户","315040");
	String result = Optional.ofNullable(user)
  		.flatMap(User::getAddress)
		.flatMap(Address::getCountry)
  		.map(Country::getPostcode)
  		.orElse("未知的");

六、Optional错误用法的例子:

  • 不适合使用情形之一:直接使用optional与空(null)进行条件判断比较:if (optional != null)
	// 错误示例
	Optional<String> optional = Optional.ofNullable(null);
	if (optional != null) { // 无意义的检查
    	System.out.println(optional.get());
	}

由于Optional本身就是用来避免显式地进行空值(null)检测的,直接显式地用if (optional != null)检查是没有意义的,这个判断语句永远是false。
解决办法:可使用optional.isPresent()或optional.orElse(…)实现此功能。

  • 不适合使用情形之二:使用Optional作为方法或构造器的参数。
    将Optional对象作为方法或构造器的参数时。这样做会让代码变得复杂,完全没有必要。
	User user = new User(56, "测试用户", Optional.empty());
  • 不适合使用情形之三:将Optional用于作为集合的参数,集合已经能很好地处理空集合的情形,没必要使用Optional包装集合。

结束语:
Optional是 Java 语言的有益补充它旨在避免空指针异常( NullPointerException),尽管还不能完全消除这些异常。
但Java 8对Optional的精心设计,自然融入了函数式编程,并增强了函数式编程的功能。

参考文献:

  • Java高级之告别空指针:Java Optional 详解与实战指南
  • Java中的Optional类详细解读
  • 理解、学习与使用 Java 中的 Optional

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stm32与ht7038的项目

最近做了一个stm32与ht7038的数据采集项目 硬件包含太阳能充电电路 ht7038采集芯片电路 buck电路 stm32最小系统电路和lora模块电路 硬件PCB如下图所示 ht7038的程序如下所示ht7038.c #include "ht7038.h" #include "stm32l0xx_hal_spi.h"typedef uint8…

AbsPlus框架介绍2

ABSPlus框架以其集成的多功能性在市场上脱颖而出。它不仅提供美观且符合主流风格的页面设计&#xff0c;还支持灵活的流程配置&#xff0c;包括算法处理流程和页面审批流程。在众多业务系统中&#xff0c;流程管理往往是核心且复杂的挑战&#xff0c;涉及数据库设计、页面开发以…

springboot基于微信小程序的食堂预约点餐系统

摘 要 基于微信小程序的食堂预约点餐系统是一种服务于学校和企事业单位食堂的智能化解决方案&#xff0c;旨在提高食堂就餐的效率、缓解排队压力&#xff0c;并优化用户的就餐体验。系统作为一种现代化的解决方案&#xff0c;为食堂管理和用户就餐提供了便捷高效的途径。它不仅…

免费的视频混剪综合处理工具介绍与下载

免费的视频混剪综合处理工具 软件截图 功能 支持&#xff1a; 这个软件主要用于视频的批量处理&#xff0c;包括添加水印、裁剪、画中画、去水印、去头尾、变速、文本和背景音乐等功能。以下是界面中一些主要功能的介绍&#xff1a; 视频队列&#xff1a;显示当前待处理的视…

2024年亚太数学建模竞赛问题C宠物产业及相关产业发展分析与对策

随着人们消费理念的发展&#xff0c;随着经济的快速发展和人均收入的提高&#xff0c;宠物产业作为一个新兴产业在全球范围内逐渐积聚势头。1992年&#xff0c;中国小动物保护协会成立&#xff0c;随后1993年&#xff0c;皇家狗狗、玛氏等国际宠物品牌进入中国市场。随着“宠物…

如何默认VS2019用管理员方式打开

1.通过快捷方式找到“Visual Studio 2019”所在文件夹。 2.继续在"Visual Studio 2019"右键菜单&#xff0c;打开“devenv.exe”所在文件夹。 3.在“devenv.exe”右键菜单&#xff0c;选择“兼容性疑难解答”。 4.选择“疑难解答程序”。 5.选择勾选“该程序需要附加…

鸿蒙UI开发与部分布局

UI开发 1. 布局概述 1.1 开发流程 1.先确定开发流程 -> 2.分析页面元素构成 ->3.选用合适的布局容器组件 1.3 布局元素组成&#xff1a;盒模型 2.1 布局分类 2.1 线性布局 线性布局是开发中最常用、最基础的布局&#xff0c;通过线性容器Row和Column构建 2.1.1 线性布…

Python中Tushare(金融数据库)入门详解

文章目录 Python中Tushare&#xff08;金融数据库&#xff09;入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…

性能优化(二):ANR

介绍 ANR全称Application Not Responding&#xff0c;意思就是程序未响应。如果一个应用无法响应用户的输入&#xff0c;系统就会弹出一个ANR对话框&#xff0c;用户可以自行选择继续等待亦或者是停止当前程序。 Android系统会监控程序的响应状况&#xff0c;一旦出现下面情况…

神经网络问题之:梯度不稳定

梯度不稳定是深度学习中&#xff0c;特别是在训练深度神经网络时常见的一个问题&#xff0c;其本质涉及多个方面。 一、根本原因 梯度不稳定问题的根本原因在于深度神经网络的结构和训练过程中的一些固有特性。随着网络层数的增加&#xff0c;梯度在反向传播过程中会逐层累积变…

弹幕发送功能‘简单’实现

导入依赖 <!-- websocket弹幕依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>后端代码 package com.by.danmaku;import org.springfra…

RPC-健康检测机制

什么是健康检测&#xff1f; 在真实环境中服务提供方是以一个集群的方式提供服务&#xff0c;这对于服务调用方来说&#xff0c;就是一个接口会有多个服务提供方同时提供服务&#xff0c;调用方在每次发起请求的时候都可以拿到一个可用的连接。 健康检测&#xff0c;能帮助从连…

奶龙IP联名异军突起:如何携手品牌营销共创双赢?

在快节奏的互联网消费时代&#xff0c;年轻消费群体对产品和品牌的要求越来越挑剔。因此在品牌年轻化的当下&#xff0c;一方面需要品牌自身形象也要不断追求时代感&#xff0c;另一方面品牌也需要不断引领消费者需求&#xff0c;提升竞争力和产品力。 奶龙作为近年来异军突起…

Flutter:photo_view图片预览功能

导入SDK photo_view: ^0.15.0单张图片预览&#xff0c;支持放大缩小 import package:flutter/material.dart; import package:photo_view/photo_view.dart;... ...class _MyHomePageState extends State<MyHomePage>{overrideWidget build(BuildContext context) {return…

第二课 Model模型资源导入设置检查与优化

上期我们学习了最简单的audio音效的优化&#xff0c;接下来我们继续model模型资源的优化&#xff0c;我将汇总各路大神关于模型优化的思路和方法供你和我学习。 首先我们还是要把我们优化的目标重申一遍&#xff1a; 优化的目标 1.文件体积尽可能小 2.内存占用尽可能小 3.…

RabbitMQ实现异步下单与退单

前言&#xff1a; 在电商项目中的支付模块也是一个很重要的模块&#xff0c;其中下订操作以及退订操作就是主要的操作。其次的下单是同步下单&#xff0c;也就是第三方支付、数据库扣减、积分增加、等等其他业务操作&#xff0c;等待全部执行完毕后向用户返回成功响应请求。对…

macOS 无法安装第三方app,启用任何来源的方法

升级新版本 MacOS 后&#xff0c;安装下载的软件时&#xff0c;不能在 ”安全性与隐私” 中找不到 ”任何来源” 选项。 1. 允许展示任何来源 点击 启动器 (Launchpad) – 其他 (Other) – 终端 (Terminal)&#xff1a; 打开终端后&#xff0c;输入以下代码回车&#xff1a; …

微服务即时通讯系统的实现(服务端)----(1)

目录 1. 项目介绍和服务器功能设计2. 基础工具安装3. gflags的安装与使用3.1 gflags的介绍3.2 gflags的安装3.3 gflags的认识3.4 gflags的使用 4. gtest的安装与使用4.1 gtest的介绍4.2 gtest的安装4.3 gtest的使用 5 Spdlog日志组件的安装与使用5.1 Spdlog的介绍5.2 Spdlog的安…

欧洲新车安全评鉴协会(Euro NCAP)2026 年规程的 5 项关键更新

数十年来,欧洲新车安全评鉴协会为全球车辆安全评级树立了黄金标准。该协会向来以引领潮流著称,常常在法规强制要求之前数年就采用新的安全技术。 随着 2026 年欧洲新车安全评鉴协会的更新即将到来,汽车行业急切地想知道需要格外密切关注哪些特性和技术。 尽管欧洲新车安全…

Jenkins迁移数据目录

查看当前容器挂载的目录 [roottest-server01 ~]# docker inspect -f "{{.Mounts}}" jenkins [{bind /etc/localtime /etc/localtime true rprivate} {bind /opt/jenkins_data /var/jenkins_home true rprivate}]复制数据目录到数据盘 [roottest-server01 opt…