万字长文分析函数式编程

目录

一.认识函数式编程

一、函数式编程的定义

二、函数式编程的思想

三、函数式编程的特点

四、函数式编程的应用

二.Lambda表达式

三.Stream流

3.1 创建流对象

3.2 注意事项

3.3 Stream流的中间操作

filter

map

distinct

sorted

limit

skip

flatMap

3.4 Stream流的中间操作

max&min

可以用来求流中的最值

collect

Collectors.toMap

Collectors中还有分组等功能

查找与匹配

allMatch

findAny

findFirst

reduce归并

四. Optional流

 4.1 概述

4.2 安全的消费值

 4.3 安全获取值

1. orElseGet

2. orElseThrow

 4.4 过滤

 4.5 数据转换Map

五.函数式接口

5.1 概述

5.2 函数式接口介绍

1. Consumer消费接口

2. Function计算转换接口

3. Predicate判断接口

4. Supplier生产接口

5.3 常用默认方法

使用场景在自定义函数式方法时使用

and

or 或者

negate取反

六.方法引用

6.1 认识方法引用

基本用法

基本格式

6.2 语法详解(了解)

引用类的静态方法

引用对象的实例方法

引用类的实例方法

构造器引用

七. 高级用法

7.1 基本数据类型优化

7.2 并行流


一.认识函数式编程

函数式编程是一种编程范式,它以函数作为第一对象,将计算过程视为数学函数的求值,从而避免改变状态和使用可变数据。以下是对函数式编程及其思想的详细解释:

一、函数式编程的定义

函数式编程把计算当成是数学函数的求值,注重描述而非具体执行步骤。在函数式编程中,函数是核心的概念,它们可以接受输入(参数),并返回输出(结果)。这些函数可以像其他数据类型一样被传递和操作,从而允许开发者构建高度模块化和可重用的代码。

二、函数式编程的思想

1.数学抽象

     函数式编程是面向数学的抽象,将计算描述为一种表达式求值。在函数式编程中,函数的概念与数学中的函数类似,即输入元素的集合到可能的输出元素的集合之间的映射关系。

2.不可变性

      函数式编程强调数据的不可变性,即数据一旦创建就不能被改变。这有助于减少程序中的错误和复杂性,因为开发者不需要担心数据在何时何地被修改。

3.声明式编程

  • 函数式编程是一种声明式的编程范式,通过表达式和声明而不是语句来编程。这意味着开发者可以告诉计算机想要的结果,而不是具体如何达到这个结果。

4.函数组合

  • 函数式编程允许开发者通过组合不同的函数来构建更大的函数,以实现更加抽象和复杂的行为。这种组合方式使得代码更加模块化和易于理解。

5.高阶函数

  • 高阶函数是指将一个或多个函数装入另一个函数中,这个函数会有相关操作并且返回一个全新的函数。高阶函数使得函数式编程更加灵活和强大。

三、函数式编程的特点

  1. 无状态改变
  • 在函数式编程中,尽量避免使用可变的状态。所有的计算都是基于输入参数进行的,不依赖于任何外部状态。

     2.引用透明

  • 由于函数式编程中的函数是无副作用的(即不会改变外部状态),因此函数的结果仅取决于其输入参数。这使得函数在程序中是引用透明的,可以更容易地进行优化和并行处理。

    3.模块化

  • 函数式编程通过函数组合和高阶函数等特性,使得代码更加模块化。每个函数都是独立的,可以单独进行测试和调试。

    4. 易于并行化

  • 由于函数式编程中的计算是基于输入参数的,不依赖于外部状态,因此可以更容易地进行并行化处理。这有助于提高程序的性能。

四、函数式编程的应用

函数式编程是一种强调数学抽象、不可变性、声明式编程、函数组合和高阶函数等特性的编程范式。它的思想是将计算过程视为数学函数的求值,并通过构建高度模块化和可重用的代码来实现更加高效和可靠的软件开发。

二.Lambda表达式

2.1 Lambda表达式的基本作用?

简化函数式接口的匿名内部类的写法

2.2 Lambda表达式有什么使用前提?

必须是接口的匿名内部类,接口中只能有一个抽象方法

2.3 Lambda的好处?

Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码 ,它可以写出更简洁,更灵活的代码,作为一种更加紧凑的代码风格,使java语言表达能力得到了提升

函数式编程(Functional programming)是一种思想特点。

函数式编程思想,忽略面向对象的复杂语法,强调做什么,而不是谁去做

lambda表达式就是函数式思想的体现

Lambda表达式的省略写法:

省略核心: 可推导,可省略

  • 参数类型可以省略不写
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略
  • 如果Lambda表达式的方法体只有一行大括号,分号,return可以省略不写,需要同时省略

三.Stream流

Stream流可以被用来对集合或数组进行链状流式的操作。可以帮方便的让我们对集合或者数组操作。

3.1 创建流对象

3.1.1 单列集合获取流对象

List<Author> authors = getAuthors();
authors.stream().distinct().filter(author -> author.getAge()>18).forEach(author -> System.out.println(author.getName()));

3.1.2 数组获取流对象

Integer[]integers ={1,2,3,4,5,6,7,8};
Stream<Integer> stream = Arrays.stream(integers);
stream.distinct().filter(new Predicate<Integer>() {@Overridepublic boolean test(Integer integer) {return integer>5;}}).forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});

3.1.3 双列集合获取流对象

Map<String,String>maps=new HashMap<String,String>();
// entrtSet把键值对封装为一个单列集合
Stream<Map.Entry<String, String>> stream1 = maps.entrySet().stream();stream1.forEach(new Consumer<Map.Entry<String, String>>() {@Overridepublic void accept(Map.Entry<String, String> stringStringEntry) {System.out.println(stringStringEntry.getKey());}
});

3.2 注意事项

  • 惰性求值(如果没有终结操作),那么中间操作是不会得到执行的
  • 流是一次性的(一旦一个流对象经过一个终结操作后,这个流就不能再被使用)
  • 不会影响原来数据(我们在流中可以对数据做很多处理。但是正常情况下是不会影响原来集合中的元素的,这往往也是我们期待的)

不创建流对象,每个流对象只可以使用一次

在每次使用流时,直接stream()

List<Author> authors = getAuthors();
authors.forEach(System.out::println);
authors.stream().flatMap(author -> author.getBooks().stream()).forEach(System.out::println);

3.3 Stream流的中间操作

filter

可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中

authors.stream().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getName().length()>1;}

map

可以把流中的元素进行计算或转换

// 元素类型转换
authors.stream().map(new Function<Author, String>() {@Overridepublic String apply(Author author) {return author.getName();}
}).forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}
});
authors.stream().map(new Function<Author, Integer>() {@Overridepublic Integer apply(Author author) {return author.getAge()+10;}
}).forEach(System.out::println);

distinct

可以去除流中的重复元素

注意:distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意equals方法。

sorted

重载的两个方法:

无参数sorted()

  • 需要实现Comparable接口
  • 重写compareTo方法
public class Author implements Comparable<Author>{@Overridepublic int compareTo(Author o) {return this.getAge()-o.getAge();}

有参数Sorted()

public static void testThree(){List<Author> authors = getAuthors();authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o1.getAge()-o2.getAge();}}).forEach(author -> System.out.println(author.getAge()));}

limit

可以设置流的最大长度,超出的部分将被抛弃

// 打印其中年龄最大的两个作家的姓名
authors.stream().distinct().sorted(new Comparator<Author>() {@Overridepublic int compare(Author o1, Author o2) {return o2.getAge()-o1.getAge();}}).limit(2).forEach(System.out::println);

skip

跳过流中的前n个元素,返回剩下的元素

flatMap

map只能把一个对象转成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素

可以把集合中的元素转为一个个对象类型来操作

List<Author> authors = getAuthors();
// 打印现有数据的所有分类
authors.stream().flatMap( author -> author.getBooks().stream()).distinct().flatMap( book -> Arrays.stream(book.getCategory().split(","))).distinct().forEach(System.out::println);

3.4 Stream流的中间操作

max&min

可以用来求流中的最值

List<Author> authors = getAuthors();
// 获取这些作家的最高分和最低分
val max = authors.stream().flatMap(author -> author.getBooks().stream()).map(Book::getScore).max(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 - o2;}});
System.out.println(max);

collect

把当前流转换成一个集合

Collectors.toList()

Collectors.toSet()

public static void testNight(){List<Author> authors = getAuthors();val collect = authors.stream().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() > 1;}}).collect(Collectors.toSet());System.out.println(collect);
}

Collectors.toMap

List<Author> authors = getAuthors();
val collect = authors.stream().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(collect);

Collectors中还有分组等功能

查找与匹配

anyMatch

可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型

allMatch

可以用来判断是否都符合匹配条件,结果为boolean类型。如果都符合结果为true,否则为false。

findAny

获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素

findFirst

获取流中的第一个元素

reduce归并

  • Reduce 原意:减少,缩小
  • 根据指定的计算模型将Stream中的值计算得到一个最终结果
  • 例:求最大,最小,求和,乘积,商等等

reduce的作用是把stream流中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿到流中的元素和初始化值进行计算,计算结果再和后面的元素计算。

计算完一次后会重新赋值给result,继续进行下一次计算

 U result = identity;for (T element : this stream)    result = accumulator. apply(result, element)return result;

两个形参的使用方法

  • Integer.MIN_VALUE为传入值,会传给方法中第一个参数result
  • element是遍历中拿到的stream流中的元素值
List<Author> authors = getAuthors();
Integer reduce = authors.stream().map(author -> author.getAge()).reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {@Overridepublic Integer apply(Integer result, Integer element) {return result > element ? result : element;}});
System.out.println(reduce);

四. Optional流

 4.1 概述

我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断

而过多的判断语句会让我们的代码显得臃肿不堪

所以在JDK8引入了Optional,养成使用Optional的习惯后,可以写出更加优雅的代码来避免空指针异常

4.2 安全的消费值

我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时我们可以使用ifPresent方法来消费其中的值

这个方法会判断其内封装的数据是否为空,不为空才会执行具体的消费代码。这样使用起来就更加安全了。

Optional<Author> authorss = getAuthorss();
authorss.ifPresent(author -> System.out.println(author.getName()));

 4.3 安全获取值

如果我们期望安全的获取值。我们不推荐使用get方法,而是使用Optional提供的以下方法。

1. orElseGet

获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返回。

val author = authorss.orElseGet(Author::new);

2. orElseThrow

获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出

val author = authorss.orElseThrow(new Supplier<Throwable>() {@Overridepublic Throwable get() {return new RuntimeException("值为null");}
});

 4.4 过滤

我们可以使用filter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象

// 这里optionalAuthor是没有数据的
val optionalAuthor = authorss.filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() > 50;}
});
System.out.println(optionalAuthor.orElseGet(()->new Author()).getName());

 4.5 数据转换Map

Optional还提供了map可以让我们对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全,当对象层级很深时,使用map进行类型转换可以有效降低if深度,使代码更加清晰,提高可读性

Optional<Author> authorss = getAuthorss();
authorss.map(Author::getBooks).ifPresent(System.out::println);

五.函数式接口

5.1 概述

只有一个抽象方法的接口我们称之为函数接口

JDK的函数式接口都加上了@FunctionalInterface注解进行标识

但是无论方法是否加上该注解只要接口中只有一个抽象方法,都是函数式接口

5.2 函数式接口介绍

1. Consumer消费接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费

@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t);

2. Function计算转换接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行计算或者转换,把结果返回

@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);

3. Predicate判断接口

根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果。

@FunctionalInterface
public interface Predicate<T> {/*** Evaluates this predicate on the given argument.** @param t the input argument* @return {@code true} if the input argument matches the predicate,* otherwise {@code false}*/boolean test(T t);

4. Supplier生产接口

  • 根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回

例如:collect方法

authors.stream().collect()
@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}

5.3 常用默认方法

使用场景在自定义函数式方法时使用

and

predicate对象的方法

authors.stream().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge()>17;}}.and(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getName().length()>1;}}))

or 或者

authors.stream().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge()>17;}}.or(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getName().length()>1;}}))

negate取反

六.方法引用

6.1 认识方法引用

我们在使用lambda时,如果方法体只有一个方法的调用的话(包含构造方法),我们可以使用方法引用进一步简化代码。

基本用法

我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们只需要在写完lmbda方法后,发现方法体只有一行代码,并且是方法的调用时,使用快捷键尝试是否能够转换成方法引用即可。

基本格式

类名或者对象名::方法名

6.2 语法详解(了解)

引用类的静态方法

格式:

类名::方法名

使用前提:

如果我们再重写方法的时候,方法体中只有一行代码,并且这行代码调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。

引用对象的实例方法

格式:

对象名::方法名

如果我们再重写方法的时候,方法体中只有一行代码,并且这行代码调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法。

引用类的实例方法

格式:

类名::方法名

使用前提:

如果我们再重写方法的时候,方法体中只有一行代码,并且这行代码调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。

构造器引用

如果方法体中的一行代码是构造器的话就可以使用构造器引用

格式:

类名::new

使用前提:

如果我们再重写方法的时候,方法体中只有一行代码,并且这行代码调用了某个类的构造方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。

七. 高级用法

7.1 基本数据类型优化

我们之前用到的很多Stream的方法由于都使用到了泛型。所以涉及到的参数和返回值都是引用数据类型。

即使我们操作的都是整数小数,但是实际使用的都是他们的包装类。JDK5中引入的自动装箱和拆箱肯定是要消耗时间的。虽然这个时间消耗很小。但是在大量的数据不断地重复装箱拆箱的时候,就不该无视这个时间消耗了。

所以为了让我们能够对这部分的时间消耗进行优化。Stream还提供了很多专门针对基本数据类型的方法。

如:mapToInt,maoToLong,mapToDouble,flatMapToInt,flatMapToDouble等

直接将数据类型转换为如int,这样在计算值时就不要进行拆箱和装箱操作

authors.stream().mapToInt(new ToIntFunction<Author>() {@Overridepublic int applyAsInt(Author value) {return value.getAge();}})

7.2 并行流

当流中有大量元素时,我们可以使用并行流去提高操作的效率。其实并行流就是把任务分配给多个线程去完成。如果我们自己去用代码实现的话其实会非常的复杂,并且要求对并发编程有足够的理解和认识。而如果我们使用Stream的话,我们只需要修改一个方法的调用就可以使用并行流来帮助我们实现,从而提高效率。

parallel方法可以把串行流转换成并行流。

也可以通过parallelStream直接获取并行流对象

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DOM 规范 — MutationObserver 接口

前言 最近在重学 JavaScript 中&#xff0c;再一次接触到了 MutationObserver 内容&#xff0c;接着联想到了 Vue 源码中有使用过这个接口&#xff0c;因此觉得有必要对 MutationObserver 接口进行相关了解和学习。 下面是 vue 源码中关于 MutationObserver 接口使用的代码&a…

灰狼优化算法

一、简介 1.1 灰狼优化算法-Grey Wolf Optimizer 通过模拟灰狼群体捕食行为&#xff0c;基于狼群群体协 作的机制来达到优化的目的。&#xff27;&#xff37;&#xff2f;算法具有结构简单、需 要调节的参数少、容易实现等特点&#xff0c;其中存在能够自适应调整 的收敛因子…

AI 写作(五)核心技术之文本摘要:分类与应用(5/10)

一、文本摘要&#xff1a;AI 写作的关键技术 文本摘要在 AI 写作中扮演着至关重要的角色。在当今信息爆炸的时代&#xff0c;人们每天都被大量的文本信息所包围&#xff0c;如何快速有效地获取关键信息成为了一个迫切的需求。文本摘要技术正是为了解决这个问题而诞生的&#x…

【 ElementUI 组件Steps 步骤条使用新手详细教程】

本文介绍如何使用 ElementUI 组件库中的步骤条组件完成分步表单设计。 效果图&#xff1a; 基础用法​ 简单的步骤条。 设置 active 属性&#xff0c;接受一个 Number&#xff0c;表明步骤的 index&#xff0c;从 0 开始。 需要定宽的步骤条时&#xff0c;设置 space 属性即…

尽量通俗易懂地概述.Net U nity跨语言/跨平台相关知识

本文参考来自唐老狮,Unity3D高级编程:主程手记,ai等途径 仅作学习笔记交流分享 目录 1. .Net是什么? 2. .Net框架的核心要点? 跨语言和跨平台 .Net x Unity跨平台发展史 Net Framework 2002 Unity跨平台之 Mono 2004 Unity跨平台之 IL2CPP 2015 二者区别 .NET Core …

基于yolov8、yolov5的番茄成熟度检测识别系统(含UI界面、训练好的模型、Python代码、数据集)

摘要&#xff1a;番茄成熟度检测在农业生产及质量控制中起着至关重要的作用&#xff0c;不仅能帮助农民及时采摘成熟的番茄&#xff0c;还为自动化农业监测提供了可靠的数据支撑。本文介绍了一款基于YOLOv8、YOLOv5等深度学习框架的番茄成熟度检测模型&#xff0c;该模型使用了…

应用程序部署(IIS的相关使用,sql server的相关使用)

数据服务程序&#xff08;API&#xff09;部署 1、修改配置文件 打开部署包中的web.config配置文件&#xff0c;确认数据库登录名和密码正确 修改ip为电脑IP&#xff08;winR输入cmd&#xff0c;输入ipconfig&#xff0c;IPv4对应的就是本机IP&#xff09; 2、打开IIS&#x…

网页版五子棋——对战模块(服务器端开发②)

前一篇文章&#xff1a;网页版五子棋——对战模块&#xff08;服务器端开发①&#xff09;-CSDN博客 项目源代码&#xff1a;Java: 利用Java解题与实现部分功能及小项目的代码集合 - Gitee.com 目录 前言 一、创建并注册 GameAPI 类 1.创建 GameAPI 类 2.注册 GameAPI 类 …

STM32单片机WIFI语音识别智能衣柜除湿消毒照明

实践制作DIY- GC0196-WIFI语音识别智能衣柜 一、功能说明&#xff1a; 基于STM32单片机设计-WIFI语音识别智能衣柜 二、功能介绍&#xff1a; STM32F103C系列最小系统板LCD1602显示器ULN2003控制的步进电机&#xff08;柜门开关&#xff09;5V加热片直流风扇紫外消毒灯DHT11…

网络远程操控

1.给两个设备配上ip地址让他们能通 2.开启远程管理功能&#xff0c;打开telnet 3.创建远程管理的账号和密码&#xff0c;账号权限 输入system-view进入视图&#xff0c;不敲这个命令不能进行配置 配好ip后进入AR1ping一下AR2的ip看看通不通&#xff0c;接着进入AR2开启telnet权…

【go从零单排】Timer、Epoch 时间函数

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;time.Timer 是一个用于在指定时间后执行操作的计时器。…

鸿蒙自定义UI组件导出使用

上期讲解了在Entry入口写了一个系统的下拉列表组件&#xff0c;如果我们想要封装一个可供复用的组件供团队其他人使用&#xff0c;那么需要掌握一下自定义组件的写法&#xff1a; 1、自定义可导入组件 - export 声明模块 如果要定义一个在外部可使用的组件 , 需要再定义组件…

Web大学生网页作业成品——婚礼婚纱网页设计与实现(HTML+CSS)(6个页面)

&#x1f389;&#x1f389;&#x1f389; 常见网页设计作业题材有**汽车、环保、明星、文化、国家、抗疫、景点、人物、体育、植物、公益、图书、节日、游戏、商城、旅游、家乡、学校、电影、动漫、非遗、动物、个人、企业、美食、婚纱、其他**等网页设计题目, 可满足大学生网…

时序数据库TimescaleDB安装部署以及常见使用

文章目录 一、时序数据库二、TimescaleDB部署1、repository yum仓库配置2、yum在线安装3、插件配置4、TimescaleDB使用登录pg创建插件使用超表 一、时序数据库 什么是时序数据库&#xff1f;顾名思义&#xff0c;用于处理按照时间变化顺序的数据的数据库即为时序数据库&#x…

Matlab: 生成对抗网络,使用Datastore结构输入mat格式数据

使用matlab的生成对抗网络&#xff08;Generative Adversarial Network&#xff0c;GAN&#xff09;以及条件CGAN时&#xff0c;案例中 的生成器的输入为图像&#xff0c;改为.mat格式输入遇到的问题。解决方法 官方资源 训练条件生成对抗网络 (CGAN)- MATLAB & Simulink-…

Linux kernel 堆溢出利用方法(二)

前言 本文我们通过我们的老朋友heap_bof来讲解Linux kernel中off-by-null的利用手法。在通过讲解另一道相对来说比较困难的kernel off-by-null docker escape来深入了解这种漏洞的利用手法。&#xff08;没了解过docker逃逸的朋友也可以看懂&#xff0c;毕竟有了root权限后&a…

设计模式:工厂方法模式和策略模式

工厂方法模式 什么是开闭原则? 开闭原则是扩展开发,对修改关闭 简单工厂(不是设计模式而是一种编程的习惯) 有三个角色 抽象产品:定义了产品的规范,描述了产品的特性和功能.具体产品:实现或者继承抽象产品的子类具体工厂:提供了创建产品的方法,调用者通过该方法获取产品 实…

深度学习代码笔记

一、U-NET 论文题目&#xff1a;U-Net: Convolutional Networks for Biomedical Image SegmentationUNet 的体系结构基于编码器-解码器范式&#xff0c;其中编码器从输入图像中提取特征&#xff0c;解码器基于这些特征生成分割图。但是&#xff0c;UNet还集成了编码器和解码器…

软件测试面试2024最新热点问题

大厂面试热点问题 1、测试人员需要何时参加需求分析&#xff1f; 如果条件循序 原则上来说 是越早介入需求分析越好 因为测试人员对需求理解越深刻 对测试工作的开展越有利 可以尽早的确定测试思路 减少与开发人员的交互 减少对需求理解上的偏差 2、软件测试与调试的关系 测…

L10.【LeetCode笔记】回文链表

目录 1.题目 2.自解 代码 提交结果 1.题目 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;tru…