1 Lambda表达式:相等于匿名内部类,实现代码作为方法的参数传统。
函数式接口 变量=(参数列表)->{
方法体
};
注意: ->操作符 分成两部分
左侧:(参数列表)
右侧: 方法体
1 左侧的类型可以省略,类型推断
2 左侧没有参数,写一个()
3 左侧有一个参数, ()可以省略
4 右侧如果只有一条语句,可以省略{},如果有返回值,只有一条语句,return省略,如果有多条语句,必须写{}
5 Labmda表达式没有生成内部类
6 访问局部变量,加上final
函数式接口:只有一个抽象方法
Consumer 消费型 有参数没有返回值
Supplier 供给型 没有参数有返回值
Function 函数型 有参数有返回值
Predicate 断言型 有参数 返回值boolean
2 方法引用: 如果方法体中只调用一条语句,可以使用方法引用
对象::实例方法
System.out::println
类名::静态方法
Integer:compare
类名::实例方法
String::equals
Employee::getName
类名::new 创建对象
Employee::new
数组引用
String[]::new
3 Stream API
流:包含对集合和数组的操作
三步
1 创建流
Stream.of()
Arrays.stream()
集合的.stream()
Stream.iterate()
Stream.generate();
2 中间操作
filter 排除不满足条件数据
limit 限制
skip 跳过
distinct 去重复
map 映射
3 终止操作
forEach();
allMatch()
anyMatch()
noneMath();
findFirst();
findAny();
count();
reduce() 归约
collect() 收集
时间和日期
LocalDate
LocalTime
LocalDateTime
Instant 时间时刻
时间矫正器
时间格式化
DateTimeFormatter
1.单元测试
2.注解
3.类加载器
1.掌握单元测试
2.掌握注解
3.理解类加载器
软件测试是程序的一种执行过程,目的是尽可能发现并改正被测试软件中的错误,提高软件的可靠性。
按照是否知道源代码
黑盒测试:不关心具体的逻辑代码,只测功能
白盒测试:测试逻辑代码
灰盒测试
从软件开发的过程
单元测试Unit Testing
集成测试Integrated Testing
系统测试System Testing
根据测试的次数
冒烟测试
压力测试
Junit是一个基于Java语言的单元测试框架。是白盒测试的一种技术。
演示测试1
public class Operation {
public int add(int x,int y) {
return x^y;
}
public int sub(int x,int y) {
return x-y;
}
}
public class OperationTest {
@Test
public void testAdd() {
Operation operation=new Operation();
int result=operation.add(20, 30);
System.out.println(result);
Assert.assertEquals(50, result);
}
@Test
public void testSub() {
Operation operation=new Operation();
int result=operation.sub(10,5);
System.out.println(result);
}
}
演示测试2
有一个学生类StudentDao,添加测试类
public class StudentDao {
public void add() {
System.out.println("添加学生");
}
public void update() {
System.out.println("更新学生");
}
}
public class StudentDaoTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("测试类执行之前。。。。。。。。。");
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("测试类执行之后。。。。。。。。。");
}
@Before
public void setUp() throws Exception {
System.out.println("方法之前执行........");
}
@After
public void tearDown() throws Exception {
System.out.println("方法之后执行........");
}
@Test
public void test() {
System.out.println("测试方法");
}
@Test
public void test2() {
System.out.println("测试方法2");
}
@Test
public void testAdd() {
StudentDao studentDao=new StudentDao();
studentDao.add();
}
@Test
public void testUpdate() {
StudentDao studentDao=new StudentDao();
studentDao.update();
}
}
注意:
①测试方法上必须使用@Test进行修饰
②测试方法必须使用public void 进行修饰,不能带任何的参数
③新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开
④测试类所在的包名应该和被测试类所在的包名保持一致
⑤测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖
⑥测试类使用Test作为类名的后缀(不是必须)
⑦测试方法使用test作为方法名的前缀(不是必须)
注释:给代码添加说明和解释,注释帮助开发人员理解程序。(Comment)
注解:给代码添加说明,这个说明给程序使用。
从 JDK 5.0 开始,Java 增加了对元数据(MetaData) 的支持, 也就是Annotation(注解)。
三个基本的 Annotation:
@Override:限定重写父类方法, 该注解只能用于方法
@Deprecated:用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告.
什么是注解
Annotation其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
注解技术的要点:
如何定义注解
如何反射注解,并根据反射的注解信息,决定如何去运行类
定义新的 Annotation 类型使用@interface关键字
声明注解的属性
注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述。
Annotation的属性声明方式:Stringname();
属性默认值声明方式:Stringname() default “xxx”;
特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")
特殊属性value[];
注解属性的类型可以是:
String类型
基本数据类型
Class类型
枚举类型
注解类型
以上类型的一维数组
案例演示1 创建和使用注解
public @interface MyAnnocation {
String name();
int num() default 10;
MyAnnocation2 anno();
}
public @interface MyAnnocation2 {
String value();
}
public class Demo1 {
@MyAnnocation(name="哈哈",num=50,anno=@MyAnnocation2(value = "xxx"))
public void show() {
System.out.println("xxxxxxx");
}
}
元 Annotation指修饰Annotation的Annotation。
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。
RetentionPolicy.CLASS: 编译器将把注解记录在 class文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
RetentionPolicy.RUNTIME:编译器将把注解记录在 class文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
@Target:指定注解用于修饰类的哪个成员.@Target 包含了一个名为value,类型为ElementType的成员变量。
@Documented:用于指定被该元 Annotation 修饰的Annotation类将被 javadoc 工具提取成文档。
@Inherited:被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的Annotation,则其子类将自动具有该注解。
案例演示2 使用反射获取注解信息
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfo {
String name();
int age() default 20;
String gender();
}
public class PersonOpe {
@PersonInfo(name="李四",age=20,gender="男")
public void show(String name,int age,String gen) {
System.out.println(name);
System.out.println(age);
System.out.println(gen);
}
}
public class Demo2 {
public static void main(String[] args) throws Exception{
PersonOpe ope=new PersonOpe();
Class<?> class1=PersonOpe.class;
Method method = class1.getMethod("show", String.class,int.class,String.class);
PersonInfo annotation = method.getAnnotation(PersonInfo.class);
String name=annotation.name();
int age=annotation.age();
String gender=annotation.gender();
method.invoke(ope, name,age,gender);
}
}
Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,Java运行时系统不需要知道文件与文件系统。
JVM中有3个默认的类加载器:
引导(Bootstrap)类加载器。由原生代码(如C语言)编写,不继承自java.lang.ClassLoader。负责加载核心Java库,存储在
扩展(Extensions)类加载器。用来在
Apps类加载器(也称系统类加载器)。根据 Java应用程序的类路径(java.class.path或CLASSPATH环境变量)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。该类由sun.misc.Launcher$AppClassLoader实现。
这三个类装载器存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下使用AppClassLoader装载应用程序的类。
public class Test{
Public static void main(String[] arg){
ClassLoader c = Test.class.getClassLoader(); //获取Test类的类加载器
System.out.println(c);
ClassLoader c1 = c.getParent(); //获取c这个类加载器的父类加载器
System.out.println(c1);
ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器
System.out.println(c2);
}
}
每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程称为类加载,这里我们需要了解一下类加载的过程,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SoNgkVA9-1575685440937)(图片\02.png)]
Java装载类使用“全盘负责委托机制”。“全盘负责”是指当一个ClassLoder
装载一个类时,除非显示的使用另外一个ClassLoder
,该类所依赖及引用的类也由这个ClassLoder
载入;“委托机制”是指先委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全方面考虑的,试想如果一个人写了一个恶意的基础类(如java.lang.String
)并加载到JVM
将会引起严重的后果,但有了全盘负责制,java.lang.String
永远是由根装载器来装载,避免以上情况发生 除了JVM默认的三个ClassLoder
以外,第三方可以编写自己的类装载器,以实现一些特殊的需求。
为什么要使用这种双亲委托模式呢?
因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法被加载。
演示错误
创建java.lang包并创建String类。
双亲委派模式工作原理
双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码,类加载器间的关系如下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBburOWz-1575685440938)(图片\01.png)]
双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这不就是传说中的实力坑爹啊。
使用类加载器加载属性文件。
案例1:Properties加载属性文件
InputStream is = Test.class.getClassLoader().getResourceAsStream("user.properties");
Properties properties=new Properties();
properties.load(new InputStreamReader(is, "utf-8"));
properties.list(System.out);
案例2:使用ResourceBundle加载属性文件
//不用带扩展名
ResourceBundle bundle = ResourceBundle.getBundle("com.qf.day19.user");
//解决中文乱码问题
System.out.println(new String(bundle.getString("name").getBytes("iso-8859-1"),"utf-8"));
System.out.println(bundle.getString("age"));
System.out.println(new String(bundle.getString("gender").getBytes("iso-8859-1"),"utf-8"));
注意:属性文件默认编码为ISO-88590-1,如果修改为utf-8需要代码中处理乱码问题。