看懂了这篇,你就懂了函数式接口

author author     2023-01-25     167

关键词:


看懂了这篇-你就懂了函数式接口

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

一、文章导读

  • 函数式接口概述
  • 自定义函数式接口
  • 常用函数式接口
  • 函数式接口的练习

二、函数式接口概述

1.函数式接口定义

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

注意事项

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

2.函数式接口格式

修饰符 interface 接口名称 
//抽象方法
public abstract 返回值类型 方法名称(可选参数信息);
//默认方法
public default 返回值类型 方法名称(可选参数信息)
//代码...

//静态方法
public static 返回值类型 方法名称(可选参数信息)
//代码...

//Object类的public方法变成抽象方法
public abstract boolean equals(Object obj);
public abstract String toString();

三、自定义函数式接口

1.自定义函数式接口举例

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

@FunctionalInterface
public interface MyFunctionalInterface
//抽象方法
public abstract void method();
//Object类的public方法变成抽象方法
public abstract boolean equals(Object obj);
public abstract String toString();
//默认方法
public default void show(String s)
//打印小写
System.out.println(s.toLowerCase());

//静态方法
public static void print(String s)
//打印大写
System.out.println(s.toUpperCase());

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

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

public class Demo01FunctionalInterface 
public static void main(String[] args)
// 调用使用函数式接口的方法
show(()->
System.out.println("Lambda执行了");
);

//定义方法使用函数式接口作为参数
public static void show(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@3d075dc0
true
world
FUNCTION

四、常用函数式接口

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

1. Supplier接口

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

1.1.抽象方法 : get

Supplier`接口中包含一个抽象方法` T get(): 用来获取一个泛型参数指定类型的对象数据。
public class Demo02Supplier 
public static void main(String[] args)
int num = getNum(() ->
return new Random().nextInt();
);
System.out.println(num);

public static int getNum(Supplier<Integer> supplier)
int num = supplier.get();
return num;

1.2.求集合元素最大值

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

代码示例:

public class Demo03Supplier 
public static void main(String[] args)
List<Integer> list = new ArrayList<>();
Collections.addAll(list,10,8,20,3,5);
printMax(()->
return Collections.max(list);
);


private static void printMax(Supplier<Integer> supplier)
int max = supplier.get();
System.out.println(max);

2. Consumer接口

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

2.1.抽象方法:accept

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

代码示例:

import java.util.function.Consumer;
//接收一个输入参数x,把x的值扩大2倍后,再+3做输出
//类似于数学中的函数: f(x) = 2*x + 3
public class Demo04Consumer
public static void main(String[] args)
int x = 3;
consumeIntNum(x,(Integer num)->
System.out.println(2*num+3);
);


/*
定义方法,使用函数式接口Consumer作为方法参数
*/
private static void consumeIntNum(int num,Consumer<Integer> function )
function.accept(num);

2.2.默认方法:andThen

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

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语句和抛出空指针异常的麻烦。
​​​andThen​​是默认方法,由Consumer的对象调用,而且参数和返回值都是Consumer对象

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

代码示例:

//接收一个字符串,先按照大写打印,再按照小写打印
/*
toUpperCase(): 把字符串变成大写
toLowerCase(): 把字符串变成小写
*/
public class Demo05Consumer
public static void main(String[] args)
String s = "Hello";
//lambda标准格式
fun(s, (String str) ->
System.out.println(s.toUpperCase());
, (String str) ->
System.out.println(s.toLowerCase());
);


/*
定义方法,参数是Consumer接口
因为要消费两次,所以需要两个Consumer接口作为参数
*/
public static void fun(String s, Consumer<String> con1, Consumer<String> con2)
//先消费一次
con1.accept(s);
//再消费一次
con2.accept(s);

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

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

public class Demo06Consumer 
public static void main(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接口作为参数
*/
public static void fun(String s, Consumer<String> con1, Consumer<String> con2)

con1.andThen(con2).accept(s);


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

andThen原理分析图解:

看懂了这篇,你就懂了函数式接口_函数式接口

注意:
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<T,R>​​接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。

3.1.抽象方法:apply

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

代码示例:

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

/*
java.util.function.Function<T,R>: 转换型接口
泛型T: 转换前的类型
泛型R: 转换后的类型

抽象方法:
R apply(T t): 根据类型T的参数获取类型R的结果 把参数t转换成R类型的结果

"123" --> 123

需求:
给你一个String类型的数字,给我转换成int数字
分析:
用Function接口
T: 转换前的类型, String
R: 转换后的类型, Integer
*/
public class Demo07Function
public static void main(String[] args)
String s = "123";
//lambda标准格式
fun(s,(String str)->return Integer.parseInt(str););

/*
定义方法,使用Function接口作为参数
*/
public static void fun(String s,Function<String,Integer> function)
Integer num = function.apply(s);
System.out.println(num);

3.2.默认方法:andThen

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

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

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

代码示例:

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

/*
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: 转换前的类型, String
R: 转换后的类型, Integer
第二个Function接口:
T: 转换前的类型, Integer
R: 转换后的类型, Integer
*/
public class Demo08Function
public static void main(String[] args)
String s = "123";
//lambda标准格式
fun(s,(String str)->
return Integer.parseInt(str);
,(Integer num) ->
return num*10;
);

/*
定义一个方法,有两个Function接口作为参数
*/
public static void fun(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方法进行演示

public class Demo09Function 
public static void main(String[] args)
String s = "123";
//lambda标准格式
fun(s,(String str)->
return Integer.parseInt(str);
,(Integer num) ->
return num*10;
);


/*
定义一个方法,有两个Function接口作为参数
*/
public static void fun(String s,Function<String,Integer> fun1,Function<Integer,Integer> fun2)
Integer num3 = fun1.andThen(fun2).apply(s);
System.out.println(num3);

运行结果仍然是1230。

andThen原理分析图解:

看懂了这篇,你就懂了函数式接口_java_02

注意:
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<T>​​接口。

4.1.抽象方法:test

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

//1.练习:判断字符串长度是否大于5
//2.练习:判断字符串是否包含"H"
public class Demo10Predicate
public static void main(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接口
*/
public static void fun(String s,Predicate<String>predicate)
boolean result = predicate.test(s);
System.out.println(result);

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

4.2.默认方法:and

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

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

代码示例:

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

public class Demo11Predicate 
public static void main(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方法的底层实现
*/
public static void fun(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作为参数

*/
public static void fun2(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源码为:

default Predicate<T> or(Predicate<? super T> other) 
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);

代码示例:

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

public class Demo12Predicate 
public static void main(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方法的底层实现
*/
public static void fun(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作为参数

*/
public static void fun2(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源代码为:

default Predicate<T> negate() 
return (t) -> !test(t);

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

import java.util.function.Predicate;

public class Demo13Predicate
private static void method(Predicate<String> predicate,String str)
boolean veryLong = predicate.negate().test(str);
System.out.println("字符串很长吗:" + veryLong);


public static void main(String[] args)
method(s -> s.length() < 5, "Helloworld");

五、总结

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

gate​​方法,正如​​​and​​和​​or`方法一样:

import java.util.function.Predicate;

public class Demo13Predicate
private static void method(Predicate<String> predicate,String str)
boolean veryLong = predicate.negate().test(str);
System.out.println("字符串很长吗:" + veryLong);


public static void main(String[] args)
method(s -> s.length() < 5, "Helloworld");

五、总结

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


nginx学习?nginx可以做什么?看完这篇你就懂了!

https://mp.weixin.qq.com/s/Viv9T1kSTePNI6O2xDzyRg 查看详情

cdn百科第六讲|怎样用cdn抵御***?看完这篇漫画你就懂了

查看详情

面试阿里,字节跳动99%会被问到的java线程和线程池,看完这篇你就懂了!

前言:最近也是在后台收到很多小伙伴私信问我线程和线程池这一块的问题,说自己在面试的时候老是被问到这一块的问题,被问的很头疼。前几天看到后帮几个小伙伴解决了问题,但是问的人有点多我一个个回答也回答不过来... 查看详情

cdn到底是个什么鬼?看完这篇你就懂了(代码片段)

CDN概念CDN全称叫做“ContentDeliveryNetwork”,中文叫内容分发网络。实际上CDN这个概念是在1996年由美国麻省理工学院的一个研究小组为改善互联网的服务质量而提出的。那么它到底是怎么改善互联网服务质量的呢?原理分析... 查看详情

,你就懂了信息安全的密码学(代码片段)

看懂这篇文章-你就懂了信息安全的密码学一、前言​一个信息系统缺少不了信息安全模块,今天就带着大家全面了解并学习一下信息安全中的密码学知识,本文将会通过案例展示让你了解抽象的密码学知识,阅读本... 查看详情

python装饰器听了n次也没印象,读完这篇你就懂了

参考技术A装饰器其实一直是我的一个"老大难"。这个知识点就放在那,但是拖延症。。。其实在平常写写脚本的过程中,这个知识点你可能用到不多但在面试的时候,这可是一个高频问题。所谓的装饰器,其实就是通过装... 查看详情

用arraylist还是linkedlist?看完你就懂了!(代码片段)

本文旨在为Java开发这择合适的顺序数据结构提供指导。ArrayList和LinkedList是Java集合框架中用来存储对象引用列表的两个类。ArrayList和LinkedList都实现List接口。首先,让我们了解一下它们最重要的父接口——List。1.List接口列表(lis... 查看详情

用arraylist还是linkedlist?看完你就懂了!(代码片段)

本文旨在为Java开发这择合适的顺序数据结构提供指导。ArrayList和LinkedList是Java集合框架中用来存储对象引用列表的两个类。ArrayList和LinkedList都实现List接口。首先,让我们了解一下它们最重要的父接口——List。1.List接口列表&... 查看详情

深度分析!面试99%被问到的多线程和并发篇,看完你就懂了

1、Java中实现多线程有几种方法继承Thread类;实现Runnable接口;实现Callable接口通过FutureTask包装器来创建Thread线程;使用ExecutorService、Callable、Future实现有返回结果的多线程(也就是使用了ExecutorService来管理前面的三种方式)。2... 查看详情

mysql7种join理论,看完你就懂了

select*fromtbl_empainnerjointbl_deptbona.deptId=b.id;select*fromtbl_empaLEFTJOINtbl_deptbona.deptId=b.id;select*fromtbl_empaRIGHTJOINtbl_deptbona.deptId=b.id;select*fromtbl_empaLEFTJOINtbl 查看详情

知道dubbo性能为什么这么强?看完你就懂了!

前言为什么Dubbo说自己性能高?高性能要从底层的原理说起,既然是一个RPC框架,主要干的就是远程过程(方法)调用,那么提升性能就要从最关键、最耗时的两个方面入手:序列化和网络通信。序列化:我... 查看详情

mysql7种join理论,看完你就懂了(代码片段)

select*fromtbl_empainnerjointbl_deptbona.deptId=b.id;select*fromtbl_empaLEFTJOINtbl_deptbona.deptId=b.id;select*fromtbl_empaRIGHTJOINtbl_deptbona.deptId=b.id;select*fromtbl_empaLEFTJOINtbl 查看详情

企业为什么要制定精益标准工时?看完这篇就懂了!

...间。那企业为什么要制定精益标准工时?看完这篇就懂了!一、精益标准工时对生产管理的重要性在企业当中,精益标准工时是衡量一切工作的水准,具有很好的客观性和公平性,这是众所周知的。 查看详情

比特币是什么-看这边你就懂了

对于比特币也许一千个人有一千种理解。本文作为入门篇,我尽量用简单易懂的语言来介绍比特币。到底什么是比特币,它到底是怎么运行的呢。比特币是什么比特币是一种基于分布式网络的数字货币。比特币系统(广义的比特... 查看详情

java读取文件内容并且换行符,看完这一篇你就懂了

正文这次写一下springboot与redis的结合,这里使用的是redis集群模式(主从),主从环境的搭建,请参考redis集群搭建搭建完redis集群环境后,开始springboot之旅1、REDIS介绍redis的介绍及应用场景参考redis介绍2、... 查看详情

如何使用tar进行文件归档,看完你就懂了(代码片段)

 什么是文件归档?文件归档就是将一组拥有相同属性的文件或目录组合到一个文件中,并从新存储它们到一个专门的目录中,以便以后在需要时进行查阅。比方说,很多情况下,我们的系统日志是有轮询的&#x... 查看详情

synchronized如何实现两个线程交替运行?看完你就懂了,列害dei(代码片段)

背景用两个线程交替输出A-Z和1-26,即一个线程输出A-Z,另一个线程输出1-26而且是交替形式线程1输出A——线程二输出1线程1输出B——线程二输出2线程1输出C——线程二输出3以此类推分析主要考察线程之间的通信,思路就是创建... 查看详情

软件测试方法有多少种?看完这篇文章你就懂了

1.按照代码运行划分静态测试指不实际运行被测对象,而只是静态地检查程序代码、界面或文档中可能存在错误的过程代码测试:主要测试代码是否符合相应的标准和规范界面测试:主要测试软件的实际界面与需求中... 查看详情