万字长文分析函数式编程

目录

一.认识函数式编程

一、函数式编程的定义

二、函数式编程的思想

三、函数式编程的特点

四、函数式编程的应用

二.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.xdnf.cn/news/14586.html

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

相关文章

移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (8) - 原生输入法

AWTK 在嵌入式平台使用内置的输入法&#xff0c;在移动设备上使用系统的原生输入法。在 AWTK-Android 和 AWTK-IOS 中&#xff0c;使用的是 SDL 封装之后的系统原生输入法。在 AWTK-HarmonyOS 中&#xff0c;要使用系统的原生输入法。需要实现 input_method 接口&#xff1a; 1…

【解决】Layout 下创建槽位后,执行 Image 同步槽位位置后表现错误的问题。

开发平台&#xff1a;Unity 6.0 编程语言&#xff1a;CSharp 编程平台&#xff1a;Visual Studio 2022   一、问题背景 | 开发库存系统 图1 位置同步失败问题 图2 位置正常同步效果表现 黑框 作用于 UnityEngine.UI.GridLayoutGruop&#xff0c;形成 4x6 布局&#xff0c;如…

【Jenkins实战】Windows安装服务启动失败

写此篇短文&#xff0c;望告诫后人。 如果你之前装过Jenkins&#xff0c;出于换域账号/本地帐号的原因想重新安装&#xff0c;你大概率会遇上一次Jenkins服务启动失败提示&#xff1a; Jenkins failed to start - Verify that you have sufficient privileges to start system…

免费,WPS Office教育考试专用版

WPS Office教育考试专用版&#xff0c;不仅满足了考试需求&#xff0c;更为教育信息化注入新动力。 https://pan.quark.cn/s/609ef85ae6d4

94个属于一区且接受医工交叉领域投稿的期刊汇总|个人观点·24-11-13

小罗碎碎念 继汇总病理AI的基础模型、病理组学&影像组学的公开数据集以后&#xff0c;我们再来盘一盘医工交叉领域有哪些热门期刊可以投稿。我会分区进行介绍&#xff0c;每个区则会进一步划分学科种类&#xff0c;方便大家选择适合自己的投稿期刊。 这期推文先分享大类属…

【插件】重复执行 pytest-repeat

安装 pip3 install pytest-repeat 用法 1.命令行 pytest --count num pytest --count 32.装饰器 pytest.mark.repeat(num) #num运行次数 pytest.mark.repeat(5)#执行结果如下&#xff1a;

el-table合并单元格之后,再进行隔行换色的且覆盖表格行鼠标移入的背景色的实现

el-table 中有现成的隔行换色功能&#xff0c;只要增加 stripe 属性即可。但是如果有单元格合并的话&#xff0c;这个属性就不可用了。这时候我们就需要动点小心思了。 基于相同字段进行合并 单元格合并&#xff1a;基于表头中的某一列&#xff0c;具有相同值的个数相加进行合…

【小白玩NAS】PVE硬盘直通

简介 在DAS架构中&#xff0c;硬盘&#xff08;NvMe除外&#xff09;通过硬盘控制器连接并由其管理。因此&#xff0c;如果将硬盘控制器直通到虚拟机&#xff0c;控制器下的所有硬盘也会间接直通至虚拟机。这样一来&#xff0c;虚拟机内会将这些硬盘视为物理磁盘&#xff0c;并…

IBM 开源的文档转化利器「GitHub 热点速览」

上周的热门开源项目&#xff0c;Star 数增长犹如坐上了火箭&#xff0c;一飞冲天。短短一周就飙升了 6k Star 的多格式文档解析和导出神器 Docling&#xff0c;支持库和命令行的使用方式。全新的可视化爬虫平台 Maxun&#xff0c;则在刚开源时便轻松斩获了 4k Star。而本地优先…

[2024最新] java八股文实用版(附带原理)---java集合篇

介绍一下常见的list实现类&#xff1f; ArrayList 线程不安全&#xff0c;内部是通过数组实现的&#xff0c;继承了AbstractList&#xff0c;实现了List&#xff0c;适合随机查找和遍历&#xff0c;不适合插入和删除。排列有序&#xff0c;可重复&#xff0c;当容量不够的时候…

windows工具 -- 使用rustdesk和云服务器自建远程桌面服务, 手机, PC, Mac, Linux远程桌面 (简洁明了)

目的 向日葵最先放弃了, todesk某些功能需要收费, 不想用了想要 自己搭建远程桌面 自己使用希望可以电脑 控制手机分辨率高一些 原理理解 ubuntu云服务器配置 够买好自己的云服务器, 安装 Ubuntu操作系统 点击下载 hbbr 和 hbbs 两个 deb文件: https://github.com/rustdesk/…

GIC寄存器介绍

往期内容 本专栏往期内容&#xff0c;interrtupr子系统&#xff1a; 深入解析Linux内核中断管理&#xff1a;从IRQ描述符到irq domain的设计与实现Linux内核中IRQ Domain的结构、操作及映射机制详解中断描述符irq_desc成员详解Linux 内核中断描述符 (irq_desc) 的初始化与动态分…

排序算法 - 冒泡

文章目录 1. 冒泡排序1.1 简介1.2 基本步骤&#xff1a;1.3 示例代码&#xff08;C&#xff09;1.4 复杂度分析1.5 动画展示 1. 冒泡排序 1.1 简介 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;其基本思想是通过相邻元素的比较和交换&#…

【机器学习】机器学习中用到的高等数学知识-2.概率论与统计 (Probability and Statistics)

概率分布&#xff1a;理解数据的分布特征&#xff08;如正态分布、伯努利分布、均匀分布等&#xff09;。期望和方差&#xff1a;描述随机变量的中心位置和离散程度。贝叶斯定理&#xff1a;用于推断和分类中的后验概率计算。假设检验&#xff1a;评估模型的性能和数据显著性。…

解决虚拟机未被自动分配ip

文章目录 1. 背景2. 解决步骤 1. 背景 从vulnhub下载的靶场文件&#xff0c;网络适配器模式设置为nat模式之后&#xff0c;启动虚拟机之后发现没有成功分配动态ip。推测是虚拟机分配的网卡名称和原先靶机作者设置网络配置文件 网络接口名称不一致导致。 2. 解决步骤 解决办法就…

人力资源招聘系统的革新之路:从传统到智能的转变

在全球化与数字化交织的今天&#xff0c;企业间的竞争日益激烈&#xff0c;而人才作为企业发展的核心驱动力&#xff0c;其重要性不言而喻。传统的人力资源招聘方式&#xff0c;如依赖纸质简历、人工筛选、面对面面试等&#xff0c;不仅效率低下&#xff0c;且难以精准匹配企业…

vue3入门和实战-vue3项目实现网址导航效果

文章目录 前言一、静态文件引入1. 下载webstack代码2. css调整3. js文件调整4.json数据文件二、项目布局和文件布局调整src/router/index.tssrc/views/Layout/LayoutIndex.vuesrc/views/Layout/IndexComponents/LayoutLeft.vuesrc/views/Home/Home.vuesrc/views/Home/component…

释放 PWA 的力量:2024 年的现代Web应用|React + TypeScript 示例

在2024年的Web开发领域&#xff0c;PWA&#xff08;Progressive Web Apps&#xff09;已经成为一个不可忽视的技术趋势。这篇文章将探讨PWA的最新发展&#xff0c;并通过实例展示如何构建一个现代PWA应用。 PWA的本质与优势 PWA本质上是一种将Web应用提升到接近原生应用体验的技…

el-form el-table 前端排序+校验+行编辑

一、页面 <template><div class"bg" v-if"formData.mouldData?.length 0">当前暂无模板&#xff0c;点击<view class"add" click"addMould">立即创建</view></div><div v-else><el-col :x…

ERA5下载数据-U850

ERA5更新后&#xff1a; 1. 升级新的cdsapirc Catalogue — 气候数据存储 --- Catalogue — Climate Data Store (copernicus.eu) ERA5下载数据页面&#xff0c;选择&#xff08;不是这个…………&#xff09; 是这个&#xff1a; ERA5 hourly data on pressure levels from…