黑马程序员技术交流社区

标题: [石家庄校区]11期就业班笔记day13-14 [打印本页]

作者: 18032086639    时间: 2018-12-2 14:57
标题: [石家庄校区]11期就业班笔记day13-14
本帖最后由 18032086639 于 2018-12-2 15:07 编辑

day14 JUnit 反射 注解
JUnit: 测试概述
1. 黑盒测试:不需要写代码, 给输入值, 看程序是否能够输出期望的值
    比如你下载一个APP, 随便点点点, APP闪退了
2. 白盒测试:需要写代码的. 关注程序具体的执行流程
    比如今天学习的JUnit
JUnit使用步骤:

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

使用断言操作来判断结果是否符合预期:

    Assert.assertEquals(期望的结果, 运算的结果);

    如果 期望的结果 和 运算的结果 相等, 则认为测试通过, 否则测试失败
测试失败的原因提示:

java.lang.AssertionError:

Expected :1    (表示我期望得到的是1)

Actual   :-1   (但是实际得到的是-1)
JUnit: @Before, @After
@Before: 修饰的方法会"在每个测试方法执行 之前"被执行
@After:  修饰的方法会"在每个测试方法执行 之后"被执行
注意:

@Before, @After 修饰的方法可以有多个, 但是谁先执行是由JUnit内部来决定的, 没有明显的规律

所以不要写多个@Before, @After 修饰的方法
反射: 概述
框架:

半成品软件. 可以在框架的基础上进行软件开发, 简化编码

比如JUnit就是一个单元测试框架, 它不是一个独立的软件, 而是和我们开发的软件结合, 简化代码测试
反射: 将类的各个组成部分, 封装为其他对象, 这就是反射机制反射: 将类的各个组成部分, 封装为其他对象, 这就是反射机制

成员变量(字段): Field类的对象

构造方法: Constructor类的对象

成员方法: Method类的对象

好处:

    1. 可以在程序运行过程中, 操作这些对象

    2. 可以解耦, 提高程序的可扩展性
Java代码在计算机中的3个阶段:Java代码在计算机中的3个阶段:

SOURCE: 源代码阶段

CLASS: 类对象阶段

RUNTIME: 运行时阶段
反射: 获取字节码对象的3种方式
获取一个类的字节码对象的3种方式:/

1. Class.forName("全类名")

    将字节码文件加载进内存,返回Class对象

    适用场景: 多用于配置文件,将类名定义在配置文件中. 读取文件, 加载类

2. 类名.class                         .

    通过类名的属性class获取

    适用场景: 多用于参数的传递  getConstructor(String.class, int.class)

3. 对象.getClass()

    getClass()方法在Object类中定义

    适用场景: 多用于对象的获取字节码的方式 p.getClass()
同一个类的字节码对象, 只有"唯一的一个"同一个类的字节码对象, 只有"唯一的一个"
反射: Class的方法概述
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容
// 成员方法
// 1. 获取成员变量们

Field[] getFields(): 获取所有 public 的成员变量

Field getField(String name): 获取指定名称的 public 的成员变量

Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符

Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符
// 2. 获取构造方法们

Constructor<?>[] getConstructors(): 获取所有 public 的构造方法

Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法

Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符
// 3. 获取成员方法们:

Method[] getMethods(): 获取所有 public 的成员方法

Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法

Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符

Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符
// 4. 获取Class对象代表的类的全类名

String getName(): 获取当前Class对象代表的类的全类名
// 5. 创建对象

T newInstance(): 使用当前类的空参构造, 创建一个对象
反射: 获取成员变量Field反射: 获取成员变量Field
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容

// 获取功能

1. 获取成员变量们

    Field[] getFields(): 获取所有 public 的成员变量

    Field getField(String name): 获取指定名称的 public 的成员变量

    Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符

    Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符
java.lang.reflect.Field: 表示一个成员变量

// 成员方法 String name;   Person p = new Person(); p2.name = "abc";

void set(Object obj, Object value): 设置指定对象的成员变量的值 field.set(p1, "abc")

Object get(Object obj): 获取指定对象的成员变量的值 field.get(p1)

void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射 field.set
反射: 获取构造方法Constructor
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容

// 获取构造方法们

Constructor<?>[] getConstructors(): 获取所有 public 的构造方法

Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法

Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符

Constructor<T> getDeclaredConstructor(Class... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符

T newInstance(): 使用当前类的空参构造创建一个对象





Constructor con = c.getConstructor(String.class, int.class);
con.newInstance("zhangsan", 18);
new Person("zhangsan", 18);
java.lang.reflect.Constructor<T>: 表示一个构造方法

// 成员方法

T newInstance(Object... initargs): 使用当前构造方法传入参数, 创建对象
反射: 获取成员方法Method
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容

// 获取成员方法们:

Method[] getMethods(): 获取所有 public 的成员方法

Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法

Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符

Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符
java.lang.reflect.Method类: 表示一个成员方法java.lang.reflect.Method类: 表示一个成员方法

// 成员方法 Person p = new Person();   p.eat("adf", 123);  

Object invoke(Object obj, Object... args): 使用指定对象和指定参数值调用此方法

String getName(): 获取方法名

void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射
反射: 利用反射实现可以运行任意类的任意方法的框架案例
补充:
java.lang.Class<T>

// 成员方法

ClassLoader getClassLoader(): 返回该类的类加载器
java.lang.ClassLoader: 类加载器 加载.class文件到内存的方法区中, 其他类型文件.propertiesjava.lang.ClassLoader: 类加载器 加载.class文件到内存的方法区中, 其他类型文件.properties

// 成员方法

InputStream getResourceAsStream(String name): 读取相对于 out/production/模块名 目录中的文件, 返回一个字节流
注解: 概念
注解: Annotation

JDK 1.5 引入. 也叫元数据, 是一种代码级别的说明

它可以声明在包, 类, 字段(成员变量), 方法, 局部变量, 方法参数等的前面, 用来对这些元素进行说明
注解: 说明程序的。给计算机看的
注释: 用文字描述程序的。给程序员看的
使用注解: @注解名称
作用分类:

1. 编写文档: 通过代码里标识的注解生成文档

    (生成API文档 @author @version @since @param @return)

2. 代码分析: 通过代码里标识的注解对代码进行分析 (使用反射)

    (JUnit提供的 @Test @Before @After)

3. 编译检查: 通过代码里标识的注解让编译器能够实现基本的编译检查

    (@Override @FunctionalInterface)
注解: JDK内置注解
JDK中预定义的一些注解:

@Override: 检测被该注解标注的方法是否是"重写"父类(接口)的

@Deprecated: 该注解标注的内容,表示已过时

@SuppressWarnings: 压制警告. 一般传递参数all  @SuppressWarnings("all")
自定义注解: 格式和本质
public interface 接口名 {}
自定义注解格式:关键字 @interface

元注解
public @interface 注解名称 {
    属性; (接口中的抽象方法)
    属性;
    属性;
    ...
   
}
@注解名称
   
注解的本质:

注解本质上就是一个接口,该接口默认继承Annotation接口

public interface MyAnno extends java.lang.annotation.Annotation {}
枚举:

enum, enumeration. JDK 1.5 引入

主要是用于定义一些"相关的"常量, 比如星期, 颜色, 用来进行区分
枚举定义方式:
public enum 枚举名 {

枚举常量1, 枚举常量2, 枚举常量3;
}
使用方式:
枚举名.常量名
自定义注解: 属性定义
属性:
接口中的"抽象方法"

属性的要求:属性的要求:
1. 属性的"返回值类型"可以是以下类型:    基本数据类型(8种)    String    枚举    注解    以上类型的数组2. 定义了属性,在使用注解时, 需要"给属性赋值" (其实是抽象方法的返回值)    1. 属性使用 default 关键字指定默认值, 则可以不赋值    2. 如果只有一个名为"value"的属性需要赋值, 则 value 可以省略, 直接写值即可

元注解:
用于描述注解的注解

常用元注解:常用元注解:
@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);数据类型 变量名 = 注解变量名.抽象方法();ProAnno proAnno = Test.class.getAnnotation(ProAnno.class);String className = proAnno.className();String methodName = proAnno.methodName();

今日API
获取一个类的字节码对象的3种方式:
1. Class.forName("全类名")2. 类名.class                         .3. 对象.getClass()

java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容
// 获取功能
// 1. 获取成员变量们
Field[] getFields(): 获取所有 public 的成员变量Field getField(String name): 获取指定名称的 public 的成员变量Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符

// 2. 获取构造方法们
Constructor<?>[] getConstructors(): 获取所有 public 的构造方法Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符

// 3. 获取成员方法们:
Method[] getMethods(): 获取所有 public 的成员方法Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符

// 4. 获取Class对象代表的类的全类名
String getName(): 获取当前Class对象代表的类的全类名

// 其他
T newInstance(): 使用当前类的空参构造创建一个对象A getAnnotation(Class<A> annotationClass): 获取当前类的注解对象ClassLoader getClassLoader(): 返回该类的类加载器

java.lang.reflect.Field: 表示一个成员变量java.lang.reflect.Field: 表示一个成员变量
// 成员方法void set(Object obj, Object value): 设置指定对象的成员变量的值Object get(Object obj): 获取指定对象的成员变量的值void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射

java.lang.reflect.Constructor<T>: 表示一个构造方法java.lang.reflect.Constructor<T>: 表示一个构造方法
// 成员方法T newInstance(Object... initargs): 使用当前构造方法传入参数, 创建对象void setAccessible(boolean flag): 注意: 构造方法不能利用此方法忽略权限, 会抛异常

java.lang.reflect.Method类: 表示一个成员方法java.lang.reflect.Method类: 表示一个成员方法
// 成员方法Object invoke(Object obj, Object... args): 使用指定对象和指定参数值调用此方法String getName(): 获取方法名void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射

java.lang.ClassLoader: 类加载器java.lang.ClassLoader: 类加载器
// 成员方法InputStream getResourceAsStream(String name): 读取相对于bin目录中的文件, 返回一个字节流

常用元注解:常用元注解:
@Target: 描述注解能够作用的位置        ElementType枚举的常用取值:                TYPE:可以作用于类上                METHOD:可以作用于方法上                FIELD:可以作用于成员变量上        示例: @Target(value = {ElementType.TYPE, ElementType.METHOD})@Retention: 描述注解被保留的阶段        RetentionPolicy枚举的取值:                SOURCE: 保留到源代码阶段                CLASS: 保留到类对象阶段                RUNTIME: 保留到运行时阶段        示例: @Retention(RetentionPolicy.RUNTIME):保留注解到class字节码文件中并被JVM读取到@Documented: 加上后, 当前注解会被抽取到api文档中@Inherited: 加上后, 当前注解会被子类继承

Stream 方法引用
流式思想概述
Stream流式思想处理数据的方式:
让代码的执行像流水线一样, 先设计好处理方案, 然后一按开关开始执行

流相比于集合的2个优点: 流相比于集合的2个优点:
1. Pipelining(管道特性): "可以链式调用"        Stream流对象的 延迟方法 调用后, 会返回新的Stream流对象, 可以链式调用        每个方法类似于一条一条的管道, 衔接了不同的处理方案2. 内部迭代特性: "不用写for循环"        集合遍历通过 Iterator 或者 增强for, 显式的在集合外部进行迭代, 这叫做外部迭代        Stream提供了内部迭代的方法 forEach(Consumer c), 可以直接调用遍历方法

使用Stream流的3个步骤:
1. 获取数据源 (从"集合"或"数组"转换为"Stream"对象)2. 数据处理 (调用延迟方法, 编写处理方案)3. 获得结果 (调用终结方法, 启动开关)

2种获取Stream流的方式
获取Stream流对象的2种方式:
1. 利用"Collection接口"中的默认方法 default Stream<E> stream() 方法: 集合转Stream对象2. 利用"Stream接口"中的静态方法 static <T> Stream<T> of(T... values): 数组转Stream对象

java.util.Collection<E>接口:java.util.Collection<E>接口:
// 默认方法default Stream<E> stream(): 将"集合"转换为Stream对象

java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
// 静态方法static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象

补充 :
// 集合转换为Stream流对象
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();                          // List集合的Stream
Set<String> set = new HashSet<>();
Stream<String> setStream = set.stream();                            // Set集合的Stream
Map<String,String> map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();                   // 键的集合的Stream
Stream<String> valueStream = map.values().stream();                 // 值的集合的Stream
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();// 键值对Stream
// 数组转换为Stream流对象
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);            
String[] array = {"a", "b", "c"};
Stream<String> arrayStream = Stream.of(array);
Stream API: 方法分类, forEach()遍历
延迟方法: (具有延迟执行的特性)
返回值类型"是Stream"类型的方法, 支持链式调用        Stream filter(): 过滤        Stream map(): 映射/转换        Stream limit(): 截取        Stream skip(): 跳过

终结方法:
返回值类型"不是Stream"类型的方法, 不支持链式调用    void forEach(): 遍历    long count(): 统计

注意:注意:
除了终结方法外, 其余方法均为延迟方法

创建数据源-> filter()过滤 | map()映射 | limit()截取 | skip()跳过 -> forEach() | count()结果
       -------------------------------------------------  

  获取流                            转换                                  聚合
                             (延迟方法)                            (终结方法)

new ArrayList().stream().filter(...).map(...).limit(...).skip(...).forEach(...);
Stream.of(1,2,3).filter(...).map(...).limit(...).skip(...).count();
java.util.stream.Stream<T>接口: 管道接口
// 抽象方法void forEach(Consumer<? super T> action): 遍历流中的元素进行逐一消费. 并不保证元素的逐一消费动作在流中是被有序执行的

Stream API: filter()过滤
java.lang.String类:
boolean startsWith(String prefix): 判断当前字符串是否以参数字符串开头

java.util.stream.Stream<T>接口: 管道接口
// 抽象方法Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流

Stream流的特点: 只能使用一次
每次调用延迟方法返回的Stream流对象, 都是经过处理后返回的"新的Stream流对象"
之前的Stream流在调用方法后, 已经使用过并关闭了, 不能再次使用, 否则会抛出异常:
java.lang.IllegalStateException: stream has already been operated upon or closed

Stream API: map()映射转换
java.util.stream.Stream<T>接口: 管道接口
// 抽象方法<R> Stream<R> map(Function<T, R> mapper): 将当前流中的T类型的元素, 转换R类型元素, 放入新流并返回

Stream API: limit()获取前n个(只要前n个)
java.util.stream.Stream<T>接口: 管道接口
// 抽象方法Stream<T> limit(long maxSize): 从流中获取前maxSize个. 如果maxSize大于等于元素个数, 则返回所有元素的流

Stream API: skip()跳过前n个(不要前n个)
java.util.stream.Stream<T>接口: 管道接口
// 抽象方法Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素. 如果n大于等于元素个数, 则全都跳过

Stream API: 静态方法concat()合并两个流        
java.util.stream.Stream<T>接口: 管道接口
// 静态方法static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流的元素, 变成一个新的流. 两个流中的元素类型必须相同, 或有共同的父类

(扩展: 收集器)
如何理解Stream流:
Stream不是集合, 也不是数组, 也不是某种数据结构, 所以Stream内部"不能存储"元素Stream是一种"函数模型", 规定一些对于集合或数组的处理方案:        在调用"延迟方法"时, 就是在编写处理方案, 但并未真正执行方案        在调用"终结方法"时, 才一次性按照处理方案来操作集合        这也是流式操作"延迟执行"的特点

收集器的作用:
收集Stream操作后的结果, 转换为其他容器 对流操作完成之后, 如果需要将其结果进行收集, 例如转换为对应的"集合"或"数组"等

java.util.stream.Stream<T>接口: 流
Object[] toArray(): 将当前Stream流对象转换为Object[]数组<R,A> R collect(Collector<? super T,A,R> collector): 将当前Stream流对象根据传入的Collector转换为集合或数组

java.util.stream.Collectors类: 收集器静态工具类, 提供不同转换方式的Collector
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)        Stream转Map集合.         Function keyMapper: 生成key的转换方式        Function valueMapper: 生成value的转换方式

方法引用
方法引用: Method Reference
如果Lambda表达式仅仅是调用一个已经存在的方法, 那就可以通过方法引用来替代Lambda表达式作用: 简化Lambda表达式:: 方法引用运算符, 它所在的表达式被称为方法引用

Lambda表达式写法:
(String s) -> System.out.println(s)   参数传递给System.out.println()方法去打印

方法引用写法:     
System.out::println引用System.out.println()方法中代码, 来作为Lambda中重写方法的实现方式

注意:
Lambda中, 重写方法的"参数", 必须是方法引用的方法"要接收的类型", 否则会抛出异常(String s) -> System.out.println(s)  方法有个参数String sSystem.out::println                  引用的println方法必须能接收String类型的s

方法引用能简化以下场景: (方法名后不要写小括号)
        场景                                                格式                          简化之前的Lambda                        方法引用简化后1. 通过对象名引用成员方法     对象名::成员方法名   ()->person.eat()          person::eat2. 通过类名引用静态方法       类名::静态方法名     i -> Math.abs(i)          Math::abs3. 通过super引用父类成员方法  super::父类方法名   ()->super.eat();          super::eat4. 通过this引用本类成员方法   this::本类方法名    ()->this.eat();           this::eat

方法引用: 通过对象名引用成员方法
通过对象名引用成员方法
对象名::成员方法名

适用场景:适用场景:
当Lambda表达式中, 仅仅是"通过某个对象, 调用已有的方法"时, 就可以用这种方式简化

方法引用: 通过类名引用静态方法
通过类名引用静态方法
类名::静态方法名  Math.abs(1)   Math::abs

适用场景:适用场景:
当Lambda表达式中, 仅仅是"通过某个类名, 调用已有的静态方法"时, 就可以用这种方式简化

方法引用: 通过super引用父类成员方法方法引用: 通过super引用父类成员方法
通过super引用父类成员方法
super::父类方法名

适用场景适用场景
当Lambda表达式中, 仅仅是"在子类中, 调用父类某个已有的方法"时, 就可以用这种方式简化

通过this引用本类成员方法:
通过this引用本类成员方法
this::本类方法名

适用场景:适用场景:
当Lambda表达式中, 仅仅是"调用本类中, 某个已有的方法"时, 就可以用这种方式简化

方法引用: 类的构造方法引用方法引用: 类的构造方法引用
引用某个类的构造方法
类名::new

使用场景使用场景
当Lambda表达式中, 仅仅是"调用某个类的构造方法, 来创建一个对象"时, 就可以用这种方式简化

方法引用: 数组的构造方法引用
引用创建数组的方法
数据类型[]::new

使用场景使用场景
当Lambda表达式中, 仅仅是"创建一个数组对象"时, 就可以用这种方式简化

APIAPI
java.util.Collection<E>接口:
// 默认方法default Stream<E> stream(): 将"集合"转换为Stream对象

java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型
// 静态方法static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流为新流// 抽象方法void forEach(Consumer<? super T> action): 遍历流中的元素进行逐一消费 (终结方法)long count(): 获取流中的元素个数 (终结方法)Stream<T> filter(Predicate<? super T> predicate): 过滤符合条件的结果. 返回过滤后的流<R> Stream<R> map(Function<? super T, ? extends R> mapper): 将T元素转换为R元素, 返回新的流Stream<T> limit(long maxSize): 从流中获取前maxSize个Stream<T> skip(long n): 从流中跳过n个元素, 获取后面的元素

方法引用能简化以下场景: (方法名后不要写小括号)方法引用能简化以下场景: (方法名后不要写小括号)
1. 通过对象名引用成员方法       对象名::成员方法名

2. 通过类名引用静态方法         类名::静态方法名

3. 通过super引用父类成员方法    super::父类方法名

4. 通过this引用本类成员方法     this::本类方法名

5. 引用某个类的构造方法         类名::new

6. 引用创建数组的方法           数据类型[]::new





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2