day13 Stream 方法引用
一 Stream流
tream流式思想:
先编写所有处理方案, 最后再统一执行方案
应用场景: 简化对集合/数组复杂操作的代码
流相比于集合的2个优点:
1. Pipelining(管道特性): "可以链式调用"
Stream流对象的 延迟方法 调用后, 会返回新的Stream流对象, 可以链式调用
每个方法类似于一条一条的管道, 衔接了不同的处理方案
2. 内部迭代特性: "不用写for循环"
集合遍历通过 Iterator 或者 增强for, 显式的在集合外部进行迭代, 这叫做外部迭代
Stream提供了内部迭代的方法 forEach(Consumer c), 可以直接调用遍历方法
使用Stream流的3个步骤:
1. 获取数据源 (从"集合"或"数组"转换为"Stream"对象)
2. 数据处理 (调用延迟方法, 编写处理方案)
3. 获得结果 (调用终结方法, 启动开关)
二 获取Stream流的方式
1.利用"Collection接口"中的默认方法 default Stream<E> stream() 方法: 集合转Stream对象
2.利用"Stream接口"中的静态方法 static <T> Stream<T> of(T... values): 数组转Stream对象
三. Stream 方法分类
1.forEach 遍历(延迟方法)
oid forEach(Consumer<? super T> action): 遍历流中的元素进行逐一消费. 并不保证元素的逐一消费动作在流中是被有序执行的
2.filter()过滤
Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流
3. map()映射转换
R> Stream<R> map(Function<T, R> mapper): 将当前流中的T类型的元素, 转换R类型元素, 放入新流并返回
4. count()计数
long count(): 获取流中的元素个数 (终结方法)
5.limit()获取前N个元素
Stream<T> limit(long maxSize): 从流中获取前maxSize个. 如果maxSize大于等于元素个数, 则返回所有元素的流
6.skip()不要前N个元素
Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素. 如果n大于等于元素个数, 则全都跳过
7.concat() 合并两个流
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流的元素, 变成一个新的流. 两个流中的元素类型必须相同, 或有共同的父类
四. 扩展
1.流转为数组
Object[] toArray(): 将当前Stream流对象转换为Object[]数组
2.流转为集合
<R,A> R collect(Collector<? super T,A,R> collector): 将当前Stream流对象根据传入的Collector转换为集合或数组
注意 Collector需要Collectors工具类的方法
static <T> Collector<T,?,List<T>> toList(): Stream转List集合
static <T> Collector<T,?,Set<T>> toSet(): Stream转Set集合
static <...> Collector<...> toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper)
五 方法引用
如果Lambda表达式仅仅是调用一个已经存在的方法, 那就可以通过方法引用来替代Lambda表达式
::方法引用运算符
注意
Lambda中, 重写方法的"参数", 必须是方法引用的方法"要接收的类型", 否则会抛出异常
1.对象名引用成员方法
对象名::成员方法名
适用场景:
当Lambda表达式中, 仅仅是"通过某个对象, 调用已有的方法"时, 就可以用这种方式简化
2 类名引用静态方法
类名::静态方法名
适用场景:
当Lambda表达式中, 仅仅是"通过某个类名, 调用已有的静态方法"时, 就可以用这种方式简化
3. 通过super引用父类成员方法
super::父类方法名
适用场景
当Lambda表达式中, 仅仅是"在子类中, 调用父类某个已有的方法"时, 就可以用这种方式简化
4 this引用本类成员方法
this ::本类方法名
适用场景:
当Lambda表达式中, 仅仅是"调用本类中, 某个已有的方法"时, 就可以用这种方式简化
5.类的构造方法引用
类名:;new
使用场景
当Lambda表达式中, 仅仅是"调用某个类的构造方法, 来创建一个对象"时, 就可以用这种方式简化
6.数组的构造方法引用
数据类型[]::new
使用场景
当Lambda表达式中, 仅仅是"创建一个数组对象"时, 就可以用这种方式简化
day14 JUnit 反射 注解
一 JUnit 单元测试
测试分类:
1. 黑盒测试:不需要写代码, 给输入值, 看程序是否能够输出期望的值
比如你下载一个APP, 随便点点点, APP闪退了
2. 白盒测试:需要写代码的. 关注程序具体的执行流程
二 测试步骤
Unit使用步骤:
1. 定义一个测试类(也叫测试用例)
包名:xxx.xxx.xx.test
被测试的类名: Calculator
对应的测试类名: CalculatorTest
2. 定义测试方法:可以独立运行
被测试的方法名: add()
对应的测试方法名: testAdd()
建议测试方法的返回值是void, 参数列表是空参
3. 在方法上加 @Test 注解
4. 在 @Test 注解上按 Alt+Enter, 选择 "Add 'JUnit4' to Classpath" 导入JUnit依赖环境
5. 在方法名上右键, 选择 "Run '方法名()'"
判定结果:
红色:失败
绿色:成功.(测试通过)
断言: Assert
使用断言操作来判断结果是否符合预期:
Assert.assertEquals(期望的结果, 运算的结果);
如果 期望的结果 和 运算的结果 相等, 则认为测试通过, 否则测试失败
测试失败的原因提示:
java.lang.AssertionError:
Expected :1 (表示我期望得到的是1)
Actual :-1 (但是实际得到的是-1)
三 JUnit: @Before, @After
@Before: 修饰的方法会"在每个测试方法执行 之前"被执行
@After: 修饰的方法会"在每个测试方法执行 之后"被执行
注意:
@Before, @After 修饰的方法可以有多个, 但是谁先执行是由JUnit内部来决定的, 没有明显的规律
所以不要写多个@Before, @After 修饰的方法
四 反射
概述: 将类的各个组成部分, 封装为其他对象, 这就是反射机制
成员变量(字段): Field类的对象
构造方法: Constructor类的对象
成员方法: Method类的对象
好处:
(1). 可以在程序运行过程中, 操作这些对象
(2). 可以解耦, 提高程序的可扩展性
file:///G:/CloudNotes/627285191@qq.com/365330a124ab47a6a5db35251d0a5a2d/%25E5%25AD%2597%25E8%258A%2582%25E7%25A0%2581.jpg
1 获取字节码对象的3中方式
(1)Class.forName("全类名")
将字节码文件加载进内存,返回Class对象
适用场景: 多用于配置文件,将类名定义在配置文件中. 读取文件, 加载类
(2)类名.class .
通过类名的属性class获取
适用场景: 多用于参数的传递 getConstructor(String.class, int.class)
(3) 3. 对象.getClass()
getClass()方法在Object类中定义
适用场景: 多用于对象的获取字节码的方式 p.getClass()
五 Class的方法概述
Class(T) 类:表示一个类的字节码对象,其中包含该类中定义的内容
成员变量
Field[] getFields(): 获取所有 public 的成员变量
Field getField(String name): 获取指定名称的 public 的成员变量
Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符
Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符
构造方法
Constructor<?>[] getConstructors(): 获取所有 public 的构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法
Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符
成员方法
Method[] getMethods(): 获取所有 public 的成员方法
Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法
Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符
Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符
Class对象代表的类的全类名
String getName(): 获取当前Class对象代表的类的全类名
创建对象
T newInstance(): 使用当前类的空参构造, 创建一个对象
六 注解
概念:说明程序的。给计算机看的
作用分类:
1. 编写文档: 通过代码里标识的注解生成文档
(生成API文档 @author @version @since @param @return)
2. 代码分析: 通过代码里标识的注解对代码进行分析 (使用反射)
(JUnit提供的 @Test @Before @After)
3. 编译检查: 通过代码里标识的注解让编译器能够实现基本的编译检查
(@Override @FunctionalInterface)
七 JDK内置注解
JDK中预定义的一些注解:
@Override: 检测被该注解标注的方法是否是"重写"父类(接口)的
@Deprecated: 该注解标注的内容,表示已过时
@SuppressWarnings: 压制警告. 一般传递参数all @SuppressWarnings("all")
八 自定义注解:格式和本质
格式: publci @interface 注解名称{
属性(接口中的抽象方法)
}
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
十 枚举
枚举:
enum, enumeration. JDK 1.5 引入
主要是用于定义一些"相关的"常量, 比如星期, 颜色, 用来进行区分
枚举定义方式:
public enum 枚举名 {
枚举常量1, 枚举常量2, 枚举常量3;
}
使用方式:
枚举名.常量名
十一 自定义注解:属性定义
属性:接口中的抽象方法
属性返回值类型
基本数据类型
String
枚举
注解
以上类型的数组
十二 元注解
常用元注解:
@Target: 描述注解能够作用的位置
ElementType枚举的常用取值:
TYPE:可以作用于类上
METHOD:可以作用于方法上
FIELD:可以作用于成员变量上
示例: @Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention: 描述注解被保留的阶段
RetentionPolicy枚举的取值:
SOURCE: 保留到源代码阶段
CLASS: 保留到类对象阶段
RUNTIME: 保留到运行时阶段
示例: @Retention(RetentionPolicy.RUNTIME):保留注解到class字节码文件中并被JVM读取到
@Documented: 加上后, 当前注解会被抽取到api文档中
@Inherited: 加上后, 当前注解会被子类继承
十三 解析注解
获取注解属性值的步骤:
1. 获取注解定义位置的对象 (Class对象(类注解), Field对象(成员变量注解), Method对象(方法注解))
2. 调用 ProAnno a = cls.getAnnotation(ProAnno.class) 方法获取注解对象
3. 通过注解对象调用抽象方法获取属性值
格式:
注解类型 注解变量名 = 被注解的类.class.getAnnotation(注解名.class);
数据类型 变量名 = 注解变量名.抽象方法();