当前位置: 首页 > news >正文

Java培训:深入解读函数式接口

函数式编程是一种编程规范或一种编程思想,简单可以理解问将运算或实现过程看做是函数的计算。 Java8为了实现函数式编程,提出了3个重要的概念:Lambda表达式、方法引用、函数式接口。现在很多公司都在使用lambda表达式进行代码编写,甚至知名的Java的插件也都在Lambda,比如数据库插件MybatisPlus。Lambda表达式的使用是需要函数式接口的支持,即lambda表达式的核心就是使用大量的函数式接口。本文带领大家全面了解函数式接口的定义和使用。

  一、文章导读

  函数式接口概述

  自定义函数式接口

  常用函数式接口

  函数式接口的练习

  二、函数式接口概述

1.函数式接口定义

  如果接口里只有一个抽象方法,那么就是函数式接口,可以使用注解(@FunctionalInterface)检测该接口是否是函数式接口,即只能有一个抽象方法。

  注意事项

  函数式接口里可以定义默认方法:默认方法有方法体,不是抽象方法,符合函数式接口的定义要求。

  函数式接口里可以定义静态方法:静态方法也不是抽象方法,是一个有具体方法实现的方法,同样也符合函数式接口的定义的。

  函数式接口里可以定义Object里的public方法(改成抽象方法):虽然它们是抽象方法,却不需要覆盖重写,因为所有接口的实现类都是Object类的子类,而在Object类中有这些方法的具体的实现。

  2.函数式接口格式

```java
修饰符 interface 接口名称 {//抽象方法publicabstract 返回值类型 方法名称(可选参数信息);//默认方法publicdefault 返回值类型 方法名称(可选参数信息){//代码...        }//静态方法publicstatic 返回值类型 方法名称(可选参数信息){//代码...        }//Object类的public方法变成抽象方法publicabstractbooleanequals(Object obj);publicabstractStringtoString();}
```

  三、自定义函数式接口

自定义函数式接口举例

  由于接口当中抽象方法的`public abstract`是可以省略的,所以定义一个函数式接口很简单:

```java
@FunctionalInterfacepublicinterfaceMyFunctionalInterface{//抽象方法publicabstractvoidmethod();//Object类的public方法变成抽象方法publicabstractbooleanequals(Object obj);publicabstractStringtoString();//默认方法publicdefaultvoidshow(String s){//打印小写System.out.println(s.toLowerCase());}//静态方法publicstaticvoidprint(String s){//打印大写System.out.println(s.toUpperCase());}}
```

  

2.自定义函数式接口的应用

  对于刚刚定义好的`MyFunctionalInterface`函数式接口,典型使用场景就是作为方法的参数:

```java
publicclassDemo01FunctionalInterface{publicstaticvoidmain(String[] args){// 调用使用函数式接口的方法show(()->{System.out.println("Lambda执行了");});}//定义方法使用函数式接口作为参数publicstaticvoidshow(MyFunctionalInterface mfi){//调用自己定义的函数式接口mfi.method();String s = mfi.toString();System.out.println(s);boolean result = mfi.equals(mfi);System.out.println(result);mfi.show("world");MyFunctionalInterface.print("function");}}
```

  

3.运行结果:

```
Lambda执行了
Demo01FunctionalInterface$$Lambda$1/1078694789@3d075dc0true
world
FUNCTION
```

  

四、常用函数式接口

  前面我们自己定义了一个函数式接口,对于一些常用的函数式接口,每次自己定义非常麻烦。JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在`java.util.function`包中被提供。这样的接口有很多,下面是最简单的几个接口及使用示例。

Supplier接口

  

`java.util.function.Supplier`接口,它意味着"供给" , 对应的Lambda表达式需要“**对外提供**”一个符合泛型类型的对象数据。

  

1.1.抽象方法 : get

  Supplier`接口中包含一个抽象方法` T get(): 用来获取一个泛型参数指定类型的对象数据。

```javapublicclassDemo02Supplier{publicstaticvoidmain(String[] args){int num =getNum(()->{returnnewRandom().nextInt();});System.out.println(num);}publicstaticintgetNum(Supplier<Integer> supplier){int num = supplier.get();return num;}}
```

  

1.2.求集合元素最大值

  使用`Supplier`接口作为方法参数类型,通过Lambda表达式求出List集合(存储int数据)中的最大值。提示:接口的泛型请使用`java.lang.Integer`类。

  代码示例:

```java
publicclassDemo03Supplier{publicstaticvoidmain(String[] args){List<Integer> list =newArrayList<>();Collections.addAll(list,10,8,20,3,5);printMax(()->{returnCollections.max(list);});}privatestaticvoidprintMax(Supplier<Integer> supplier){int max = supplier.get();System.out.println(max);}}
```

  

2. Consumer接口

  `java.util.function.Consumer`接口则正好相反,它不是生产一个数据,而是**消费**一个数据,其数据类型由泛型参数决定。

  2.1.抽象方法:accept

  `Consumer`接口中包含抽象方法`void accept(T t)`: 消费一个指定泛型的数据。

  代码示例:

```java
importjava.util.function.Consumer;//接收一个输入参数x,把x的值扩大2倍后,再+3做输出//类似于数学中的函数: f(x) = 2*x + 3publicclassDemo04Consumer{publicstaticvoidmain(String[] args){int x =3;consumeIntNum(x,(Integer num)->{System.out.println(2*num+3);});}/*定义方法,使用函数式接口Consumer作为方法参数*/privatestaticvoidconsumeIntNum(int num,Consumer<Integer> function ){function.accept(num);}}
```#### 2.2.默认方法:andThen如果一个方法的参数和返回值全都是`Consumer`类型,那么就可以实现效果:消费一个数据的时候,首先做一个操作,然后再做一个操作,实现组合。而这个方法就是`Consumer`接口中的default方法`andThen`。下面是JDK的源代码:```java
defaultConsumer<T>andThen(Consumer<?superT> after){Objects.requireNonNull(after);return(T t)->{accept(t); after.accept(t);};}
```

  

2.2.默认方法:andThen

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

```java
defaultConsumer<T>andThen(Consumer<?superT> after){Objects.requireNonNull(after);return(T t)->{accept(t); after.accept(t);};}
```

  

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

  > `andThen`是默认方法,由Consumer的对象调用,而且参数和返回值都是Consumer对象

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

  代码示例:

```java
//接收一个字符串,先按照大写打印,再按照小写打印/*toUpperCase(): 把字符串变成大写toLowerCase(): 把字符串变成小写*/publicclassDemo05Consumer{publicstaticvoidmain(String[] args){String s ="Hello";//lambda标准格式fun(s,(String str)->{System.out.println(s.toUpperCase());},(String str)->{System.out.println(s.toLowerCase());});}/*定义方法,参数是Consumer接口因为要消费两次,所以需要两个Consumer接口作为参数*/publicstaticvoidfun(String s,Consumer<String> con1,Consumer<String> con2){//先消费一次con1.accept(s);//再消费一次con2.accept(s);}}
```

  运行结果将会首先打印完全大写的HELLO,然后打印完全小写的hello。但是我们却没有使用andThen方法,其实我上面的写法,就是andThen底层的代码实现。

  为了方便大家理解,下面我们使用andThen方法进行演示。

```java
publicclassDemo06Consumer{publicstaticvoidmain(String[] args){String s ="HelloWorld";//2.lambda标准格式fun(s,(String str)->{System.out.println(s.toUpperCase());},(String str)->{System.out.println(s.toLowerCase());});}/*定义方法,参数是Consumer接口因为要消费两次,所以需要两个Consumer接口作为参数*/publicstaticvoidfun(String s,Consumer<String> con1,Consumer<String> con2){con1.andThen(con2).accept(s);}}
```

  运行结果将会首先打印完全大写的HELLO,然后打印完全小写的hello。

  andThen原理分析图解:

  

  ```txt

  注意:

  1.con1调用andThen方法,传递参数con2,所以anThen方法内部的this就是con1,after就是con2

  2.andThen方法内部调用accept方法,前面隐藏了一个this,this代表调用andThen方法的对象,就是con1

  3.andThen方法内部的t是谁?就是最后调用方法accept传递的s

  this.accept(t) <==> con1.accept(s) ①

  4.con1调用andThen方法时传递的参数是con2,所以andThen方法内部的after就是con2

  after.accept(t) <==> con2.accept(s) ②

  5.通过分析,我们发现①和②中的内容,就是之前不用andThen方法,自己进行调用的过程

  6.以上分析,仍然是按照面向对象中方法调用的思路展开的,但实质上,我们要注意,Consumer接口中的andThen方法,返回的是一个Consumer,里面采用的是lambda表达式,其实是在做函数模型的拼接,把两个函数模型con1和con2拼接出一个新的模型,返回新的模型。所以con1.andThen(con2)是把con1和con2拼接成一个新的Consumer,返回的是lambda表达式的形式

  最后调用accept(s)方法时,其实执行的是lambda表达式{}中的代码

、、、

  3. Function接口

  `java.util.function.Function`接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。

  3.1.抽象方法:apply

  `Function`接口中最主要的抽象方法为:`R apply(T t)`,根据类型T的参数获取类型R的结果。

  代码示例:

  将`String`类型转换为`Integer`类型。

```java
/*java.util.function.Function<T,R>: 转换型接口泛型T: 转换前的类型泛型R: 转换后的类型抽象方法:R apply(T t): 根据类型T的参数获取类型R的结果 把参数t转换成R类型的结果"123" --> 123需求:给你一个String类型的数字,给我转换成int数字分析:用Function接口T: 转换前的类型, StringR: 转换后的类型, Integer*/publicclassDemo07Function{publicstaticvoidmain(String[] args){String s ="123";//lambda标准格式fun(s,(String str)->{returnInteger.parseInt(str);});}/*定义方法,使用Function接口作为参数*/publicstaticvoidfun(String s,Function<String,Integer> function){Integer num = function.apply(s);System.out.println(num);}}
```

  3.2.默认方法:andThen

  `Function`接口中有一个默认的`andThen`方法,用来进行组合操作。JDK源代码如:

```java
default<V>Function<T,V>andThen(Function<?superR,?extendsV> after){Objects.requireNonNull(after);return(T t)-> after.apply(apply(t));}
```

  该方法同样用于“先做什么,再做什么”的场景,和`Consumer`中的`andThen`差不多:

  代码示例:

  将String的数字,转成int数字,再把int数字扩大10倍

```java
/*java.util.function.Function<T,R>: 转换型接口泛型T: 转换前的类型泛型R: 转换后的类型默认方法:default <V> Function<T, V> andThen(Function<R, V> after):先转换一次,再转换一次,一个挨着一个"123" --> 123 --> 1230 (扩大了10倍)需求:给你一个String类型的数字,给我转先换成int数字再给我把int数字扩大10倍分析:用2个Function接口第一个Function接口T: 转换前的类型, StringR: 转换后的类型, Integer第二个Function接口:T: 转换前的类型, IntegerR: 转换后的类型, Integer*/publicclassDemo08Function{publicstaticvoidmain(String[] args){String s ="123";//lambda标准格式fun(s,(String str)->{returnInteger.parseInt(str);},(Integer num)->{return num*10;});}/*定义一个方法,有两个Function接口作为参数*/publicstaticvoidfun(String s,Function<String,Integer> fun1,Function<Integer,Integer> fun2){//1.先转换一次Integer num1 = fun1.apply(s);//2.再转换一次Integer num2 = fun2.apply(num1);System.out.println(num2);}}
```

  第一个操作是将字符串解析成为int数字,第二个操作是乘以10。两个操作通过`andThen`按照前后顺序组合到了一起。运行结果将会打印1230。但是我们却没有使用andThen方法,其实我上面的写法,就是andThen底层的代码实现。

  > 请注意,Function的前置条件泛型和后置条件泛型可以相同。

  为了方便大家理解,下面我们使用andThen方法进行演示

  ```

publicclassDemo09Function{publicstaticvoidmain(String[] args){String s ="123";//lambda标准格式fun(s,(String str)->{returnInteger.parseInt(str);},(Integer num)->{return num*10;});}/*定义一个方法,有两个Function接口作为参数*/publicstaticvoidfun(String s,Function<String,Integer> fun1,Function<Integer,Integer> fun2){Integer num3 = fun1.andThen(fun2).apply(s);System.out.println(num3);}}
```

  运行结果仍然是1230。

  andThen原理分析图解:

  

  ```txt

  注意:

  1.fun1调用andThen方法传递参数fun2,所以andThen方法内部的this就是fun1,after就是fun2

  2.andThen方法内部直接调用apply方法,前面隐藏了一个this,this代表调用andThen方法的对象,就是fun1

  3.andThen方法内部的t是谁?就是最后调用方法apply传递的s

  this.apply(t) <==> Integer num1 = fun1.apply(s) ①

  4.fun1调用andThen方法时传递的参数是fun2,所以andThen方法内部的after就是fun2

  after.apply(this.apply(t)) <==> Integer num2 = fun2.apply(num1) ②

  5.通过分析,我们发现①和②中的内容,就是之前不用andThen方法,我们自己进行调用的过程

  6.以上分析,仍然是按照面向对象中方法调用的思路展开的,但实质上,我们要注意,Function接口中的andThen方法,返回的是一个Function,里面采用的是lambda表达式,其实是在做函数模型的拼接,把两个函数模型fun1和fun2拼接出一个新的模型,返回新的模型。所以fun1.andThen(fun2)是把fun1和fun2拼接成一个新的Function,返回的是lambda表达式的形式

  最后调用accept(s)方法时,其实执行的是lambda表达式{}中的代码

  4. Predicate接口

  有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用`java.util.function.Predicate`接口。

  4.1.抽象方法:test

  `Predicate`接口中包含一个抽象方法:`boolean test(T t)`。用于条件判断的场景:

```java
//1.练习:判断字符串长度是否大于5//2.练习:判断字符串是否包含"H"publicclassDemo10Predicate{publicstaticvoidmain(String[] args){String str ="helloWorld";//1.练习:判断字符串长度是否大于5//lambda标准格式fun(str,(String s)->{return s.length()>5;});System.out.println("-----------------");//2.练习:判断字符串是否包含"H"//lambda标准格式fun(str,(String s)->{return s.contains("H");});}/*定义一个方法,参数是Predicate接口*/publicstaticvoidfun(String s,Predicate<String>predicate){boolean result = predicate.test(s);System.out.println(result);}}
```

  条件判断的标准是传入的Lambda表达式逻辑,只要字符串长度大于5则认为很长。

  4.2.默认方法:and

  既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个`Predicate`条件使用“与”逻辑连接起来实现“**并且**”的效果时,可以使用default方法`and`。其JDK源码为:

```java
defaultPredicate<T>and(Predicate<?superT> other){Objects.requireNonNull(other);return(t)->test(t)&& other.test(t);}
```

  代码示例:

  判断一个字符串既要包含大写“H”,又要包含大写“W”

```java
publicclassDemo11Predicate{publicstaticvoidmain(String[] args){String str ="HelloWorld";//1.练习:判断一个字符串既要包含大写“H”,又要包含大写“W”//lambda标准格式fun1(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});System.out.println("------------");fun2(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});}/*演示and方法需要两个Predicate作为参数fun1方法没有使用and方法,就是p1和p2分别调用test方法,然后把结果进行&&运算--其实这是and方法的底层实现*/publicstaticvoidfun(String s,Predicate<String> p1,Predicate<String> p2){//先判断一次boolean result1 = p1.test(s);//再判断一次boolean result2 = p2.test(s);//进行&&运算boolean result = result1&&result2;System.out.println(result);}/*演示and方法需要两个Predicate作为参数*/publicstaticvoidfun2(String s,Predicate<String> p1,Predicate<String> p2){boolean result = p1.and(p2).test(s);System.out.println(result);}}```

  4.3.默认方法:or

  与`and`的“与”类似,默认方法`or`实现逻辑关系中的“**或**”。JDK源码为:

```java
defaultPredicate<T>or(Predicate<?superT> other){Objects.requireNonNull(other);return(t)->test(t)|| other.test(t);}
```

  代码示例:

  字符串包含大写H或者包含大写W”

```java
publicclassDemo12Predicate{publicstaticvoidmain(String[] args){String str ="Helloworld";//1.练习:判断一个字符串包含大写“H”或者包含大写“W”//lambda标准格式fun1(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});System.out.println("------------");fun2(str,(String s)->{return s.contains("H");},(String s)->{return s.contains("W");});}/*演示or方法需要两个Predicate作为参数fun1方法没有使用or方法,就是p1和p2分别调用test方法,然后把结果进行||运算--其实这是or方法的底层实现*/publicstaticvoidfun(String s,Predicate<String> p1,Predicate<String> p2){//先判断一次boolean result1 = p1.test(s);//再判断一次boolean result2 = p2.test(s);//进行||运算boolean result = result1||result2;System.out.println(result);}/*演示or方法需要两个Predicate作为参数*/publicstaticvoidfun2(String s,Predicate<String> p1,Predicate<String> p2){boolean result = p1.or(p2).test(s);System.out.println(result);}}```

  关于and和or方法的原理,可以参考andThen方法原理

  4.4.默认方法:negate

  “与”、“或”已经了解了,剩下的“非”(取反)也会简单。默认方法`negate`的JDK源代码为:

```java
defaultPredicate<T>negate(){return(t)->!test(t);}
```

  从实现中很容易看出,它是执行了test方法之后,对结果boolean值进行“!”取反而已。一定要在`test`方法调用之前调用`negate`方法,正如`and`和`or`方法一样:

```java
importjava.util.function.Predicate;publicclassDemo13Predicate{privatestaticvoidmethod(Predicate<String> predicate,String str){boolean veryLong = predicate.negate().test(str);System.out.println("字符串很长吗:"+ veryLong);}publicstaticvoidmain(String[] args){method(s -> s.length()<5,"Helloworld");}}
```

  

五、总结

  本文通过具体的例子,演示了函数式接口的定义和使用。以及常用的函数式接口。并给出了相关的练习题目。对于部分函数式接口中的默认方法,进行了图解分析,让你更加深刻的理解函数式接口的思想和目的。在以后实际的编程过程中,对于集合的操作,可以通过Stream流完成,而Stream流中的很多方法的参数都是函数式接口,通过本文的学习,你已经掌握了函数式接口的使用,相信后面学习Stream流是非常容易的。

相关文章:

Java培训:深入解读函数式接口

函数式编程是一种编程规范或一种编程思想&#xff0c;简单可以理解问将运算或实现过程看做是函数的计算。 Java8为了实现函数式编程&#xff0c;提出了3个重要的概念&#xff1a;Lambda表达式、方法引用、函数式接口。现在很多公司都在使用lambda表达式进行代码编写&#xff0c…...

scratch潜水 电子学会图形化编程scratch等级考试一级真题和答案解析2022年12月

目录 scratch潜水 一、题目要求 1、准备工作 2、功能实现 二、案例分析...

DNS服务器部署的详细操作(图文版)

DNS服务器的部署 打开虚拟机后查看已经开放的端口&#xff0c;可以看到没有TCP53、UDP53&#xff0c;说明DNS服务端口没有打开 打开我的电脑—双击CD驱动器— 选择安装可选的Windows组件 选择网络服务—域名系统&#xff08;DNS&#xff09;— 点击下一步后会弹出如下弹…...

Compose – List / Detail: Basics实现

Compose – List / Detail: Basics实现 在androidx中有SlidingPanelLayout可以实现折叠屏的列表详情功能&#xff0c;但在Compose 中还没有官方的实现&#xff0c;那么下面我们用Compose做一些实现。 List / Detail 我们追求的基本行为是当 UI 具有项列表时。当用户点击列表…...

【Java】TCP网络编程(字节/符流)

文章目录概念TCP网络编程ServerSocketsocket使用区别和原理演示概念 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的协议&#xff0c;用于在计算机网络中可靠地传输数据。TCP是Internet协议族中的一个核心协议&#xff0c;它在传输层提供可靠、有序、基于流的传输服…...

Linux之init.d、rc.d文件夹说明

备注&#xff1a;Ubuntu没有rc.d文件夹&#xff0c;原因看问题四 Linux的几个重要文件 rc.d&#xff0c;init.d文件夹的说明 今天在研究mysql的安装的时候&#xff0c;最后一步要创建一个软连接&#xff0c;使得mysql服务可以自启动&#xff0c;代码如下&#xff1a; ln -s…...

数据结构与算法(六):图结构

图是一种比线性表和树更复杂的数据结构&#xff0c;在图中&#xff0c;结点之间的关系是任意的&#xff0c;任意两个数据元素之间都可能相关。图是一种多对多的数据结构。 一、基本概念 图&#xff08;Graph&#xff09;是由顶点的有穷非空集合和顶点之间边的集合组成&#x…...

Kubernetes07:Service

Kubernetes07:Service 1、service存在的意义 因为Pod的IP是不断变化的&#xff0c;所以需要注册service防止pod失联 1&#xff09;为了防止Pod失联&#xff08;服务发现&#xff09; 2、定义一组Pod访问策略&#xff08;负载均衡&#xff09; 2、Pod和Service的关系-------通…...

Qt音视频开发18-不同视频打开无缝切换

一、前言 在轮询视频的时候&#xff0c;通常都是需要将之前的视频全部关闭&#xff0c;然后打开下一组视频&#xff0c;在这个切换的过程中&#xff0c;如果是按照常规的做法&#xff0c;比如先关闭再打开新的视频&#xff0c;肯定会出现空白黑屏之类的过度空白区间&#xff0…...

智能驾驶词典 --- 自动驾驶芯片梳理

0 前言 与智能驾驶相关的芯片主要分为自动驾驶芯片&#xff08;边缘端&#xff09;和智能座舱芯片两大类&#xff0c;另外衍生的相关芯片种类还有计算集群芯片&#xff08;云端&#xff09;&#xff0c; 1 自动驾驶芯片梳理 目前业内具有代表性的智驾芯片产品梳理如下。 1…...

在NVIDIA NX 配置OpenCV多版本冲突和解决的总结

Nvidia Jetson NX 环境 直接刷JetPack5.1的镜像&#xff0c;会得到如下环境 Ubuntu20.04cuda11.4TensorRT8.4cudnn8.4opencv4.5.4 而且这些源一般是从nv-xxxx等源下载的&#xff0c;打开软件Software&Update可以更该是否从这些源安装deb包。同时意味着&#xff0c;我们…...

记录pytorch安装 windows10 64位--(可选)安装paddleseg

安装完paddlepaddle之后&#xff0c;就可以安装paddleseg了。一、安装Git可以参考这个网址&#xff1a;https://blog.csdn.net/u010348546/article/details/124280236windows下安装git和gitbash安装教程二、安装paddleseghttps://github.com/PaddlePaddle/PaddleSeg记得翻墙啊这…...

UWB到底是什么技术?

什么是空间感知能力 所谓的空间感知能力&#xff0c;就是感知方位的能力。更直接一点&#xff0c;就是定位能力。说白了&#xff0c;利用UWB技术&#xff0c;手机和智能设备可以更精准地实现室内定位&#xff0c;不仅可以感知自己的位置&#xff0c;还可以感知周边其它手机或设…...

NCRE计算机等级考试Python真题(八)

第八套试题1、数据库设计中反映用户对数据要求的模式是___________。A.概念模式B.内模式C.设计模式D.外模式正确答案&#xff1a; D2、一个工作人员可使用多台计算机&#xff0c;而一台计算机被多个人使用&#xff0c;则实体工作人员与实体计算机之间的联系是___________。A.多…...

STM32之中断和事件

中断和事件什么是中断当CPU正在执行程序时&#xff0c;由于发生了某种事件&#xff0c;要求CPU暂时中断当前的程序执行&#xff0c;转而去处理这个随机事件&#xff0c;处理完以后&#xff0c;再回到原来被中断的地方&#xff0c;继续原来的程序执行&#xff0c;这样的过程称为…...

MySQL索引类型(type)分析

type索引类型 system > const > eq_ref > ref > range > index > all 优化级别从左往右递减&#xff0c;没有索引的⼀般为’all’。推荐优化目标&#xff1a;至少要达到 range 级别&#xff0c; 要求是 ref 级别&#xff0c; 如果可以是 const 最好&#xff…...

Linux | 2. 用户管理

如有错误&#xff0c;恳请指出。 1. 设置文件权限 权限设置如下&#xff1a; root表示文件所有者&#xff0c;stud1表示文件所属组。其他用户无法访问。更改指令是chown。 更改目录文件所属组&#xff1a;chown .lab lossfound/更改目录文件所有者&#xff1a;chown lab loss…...

【MySQL之SQL语法篇】系统学习MySQL,从应用SQL语法到底层知识讲解,这将是你见过最完成的知识体系

文章目录一、数据管理技术的三个阶段二、SQL语句学习1. DCL数据控制语言1.1 创建用户1.2 修改用户名1.3 修改密码1.4 删除用户1.5 授权1.6 查看权限1.7 回收权限2. DDL数据定义语言2.1 操作数据库2.2 操作数据表2.3 操作数据3. DQL数据查询语言基本语法3.1 单表查询3.1.1选择表…...

CentOS8基础篇7:Linux系统启动配置

一、Linux系统的启动过程 Linux的启动过程大体分为五个阶段&#xff1a; 1&#xff0e;计算机主机加电后&#xff0c;CPU初始化自身&#xff0c;接着在硬件固定位置执行一条指令。这条指令跳转到BIOS&#xff0c;BIOS找到启动设备并获取MBR&#xff0c;该MBR指向LILO或GRUB。 …...

vue中的$forceUpdate()、$set()

$forceUpdate() 迫使vue实例重新&#xff08;rander&#xff09;渲染虚拟dom&#xff0c;注意并不是重新加载组件。 结合vue的生命周期&#xff0c;调用 $forceupdate 后只会触发beforeupdate和updated这两个钩子函数&#xff0c;不会触发其他的钩子函数。它仅仅影响实例本身和…...

记住这3点,有效提高江苏专转本上岸率

记住这3点&#xff0c;有效提高上岸率 我们都知道&#xff0c;在江苏统招专转本考试中想岸并不是一件容易的事情。考生能否顺利上岸&#xff0c;往往受多方面因素影响&#xff0c;这其中包括&#xff1a;个人基础、学习方式、信息搜索能力。 如何提高自己的专转本上岸几率&…...

【经验总结】10年的嵌入式开发老手,到底是如何快速学习和使用RT-Thread的?(文末赠书5本)

【经验总结】一位近10年的嵌入式开发老手&#xff0c;到底是如何快速学习和使用RT-Thread的&#xff1f; RT-Thread绝对可以称得上国内优秀且排名靠前的操作系统&#xff0c;在嵌入式IoT领域一直享有盛名。近些年&#xff0c;物联网产业的大热&#xff0c;更是直接将RT-Thread这…...

人大金仓和达梦的空间数据能力对比

一、总得来说&#xff1a; 人大金仓底层更解决于pg数据库&#xff0c; 人大金仓的空间能力基于postgis能力来实现&#xff0c;能力挺强大的. 细节上人大金仓的架构上也对空间的支持框架做的比达梦更加完善。例如数据库的集群能力&#xff0c;并行计算能力&#xff0c;空间数据…...

探析集团企业 1+N 模式,重新定义集团型CRM

目录 一、客户经营、运营监控 二、流程驱动、业务成长 三、规则规范 业务治理 什么是集团型CRM【1N】&#xff1f;本文中我们可以把集团看作为“1”&#xff0c;其他分公司或组织看作为“N”。本篇我们主要分析集团CRM业务定位。 我们从企业集团总部的职能定位确定集团CRM…...

卡特兰数

文章目录1、简介1.1 何为卡特兰数1.2 卡特兰数的通项公式2、应用2.1 题目1&#xff1a;括号合法题目描述思路分析2.2 题目2&#xff1a;进出栈的方式2.2.1 题目描述2.2.2 思路分析2.3 题目3&#xff1a;合法的序列2.3.1 题目描述2.3.2 思路分析2.3.3 代码实现2.4 题目4&#xf…...

分布式任务处理

分布式任务处理 1. 什么是分布式任务调度 视频上传成功需要对视频的格式进行处理&#xff0c;如何用Java程序对视频进行处理呢&#xff1f;这里有一个关键的需求就是当视频比较多的时候我们如何可以高效处理。 如何去高效处理一批任务呢&#xff1f; 1、多线程 多线程是充…...

Linux 命令复习

常用命令 1、目录操作 cd 切换目录 cd / 切换到根目录 cd ~ 回到个人用户的主目录 ls 查看当前目录下所有文件的详细信息 list的意思 ll 查看当前目录下所有文件的详细信息 pwd 显示当前目录的全路径 . …...

leetcode 困难 —— 天际线问题(优先队列)

&#xff08;思路感觉挺明显的&#xff0c;就是一些特殊情况得考虑清楚&#xff09; 题目&#xff1a; 城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度&#xff0c;请返回 由这些建筑物形成的 天际线 。 每个建筑物的几何信息…...

离散数学笔记_第一章:逻辑和证明(2 )

1.2 命题逻辑的应用1.2.1 语句翻译 1.2.2 系统规范说明 1.2.3 布尔搜索 1.2.4 逻辑谜题泥巴孩子谜题骑士和流氓&#xff08;考研逻辑题&#xff09;1.1.2.5 逻辑电路1.2.1 语句翻译 &#x1f433;为啥要翻译语句&#xff1f; ➡因语言常常有二义性&#xff08;有歧义&#x…...

MFCC语音特征值提取算法

博主简介 博主是一名大二学生&#xff0c;主攻人工智能研究。感谢让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;c&#xff0c;Python&#xff0c;爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主&#xff0c;博主会继续更新的&#xff0c…...