A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 水煮鱼000 初级黑马   /  2019-5-19 10:11  /  615 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

十三、Lambda表达式
  • 格式:
    ​        (形式参数) -> {代码块}

    • 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
    • ->:由英文中画线和大于符号组成,固定写法。代表指向动作
    • 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容


组成Lambda表达式的三要素:
  • 形式参数,箭头,代码块

  • 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法
  • 必须有上下文环境,才能推导出Lambda对应的接口

省略的规则
  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号和分号,和return关键字

Lambda表达式和匿名内部类的区别
  • 所需类型不同

    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口

  • 使用限制不同

    • 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式

  • 实现原理不同

    • 匿名内部类:编译之后,产生一个单独的.class字节码文件
    • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成



public interface Addable {
    int add(int x, int y);
}

public interface Flyable {
    void fly(String s);
}

public class LambdaDemo {
    public static void main(String[] args) {
//        useAddable((int x,int y) -> {
//            return x + y;
//        });
        //参数的类型可以省略
        useAddable((x, y) -> {
            return x + y;
        });

//        useFlyable((String s) -> {
//            System.out.println(s);
//        });
        //如果参数有且仅有一个,那么小括号可以省略
//        useFlyable(s -> {
//            System.out.println(s);
//        });

        //如果代码块的语句只有一条,可以省略大括号和分号
        useFlyable(s -> System.out.println(s));

        //如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
        useAddable((x, y) -> x + y);
    }

    private static void useFlyable(Flyable f) {
        f.fly("风和日丽,晴空万里");
    }

    private static void useAddable(Addable a) {
        int sum = a.add(10, 20);
        System.out.println(sum);
    }
}接口组成新增默认,静态,私有方法
  • 常量
    public static final
  • 抽象方法
    public abstract
  • 默认方法(Java 8)   default     --public default void show3() { }不是抽象方法,所以不强制被重写,但是可以被重写
  • 静态方法(Java 8)   static        --private static void method() {}只能通过接口名调用,不能通过实现类名或者对象名调用
  • 私有方法(Java 9)   private     --private void show() { }

方法引用
方法引用符
::  该符号为引用运算符,而它所在的表达式被称为方法引用
引用类方法,其实就是引用类的静态方法
  • 格式
    类名::静态方法
  • 范例
    Integer::parseInt

引用对象的实例方法,其实就引用类中的成员方法
  • 格式
    对象::成员方法
  • 范例
    "HelloWorld"::toUpperCase

引用类的实例方法,其实就是引用类中的成员方法
  • 格式
    类名::成员方法
  • 范例
    String::substring
    public String substring(int beginIndex,int endIndex)

引用构造器,其实就是引用构造方法
  • l格式
    类名::new
  • 范例
    Student::new

    //Lambda简化写法
    useStudentBuilder((name,age) -> new Student(name,age));

    //引用构造器
    useStudentBuilder(Student::new);
十四、函数式接口函数式接口概述
  • 概念
    有且仅有一个抽象方法的接口
  • 如何检测一个接口是不是函数式接口
    @FunctionalInterface
    放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
  • 注意事项
    我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解

常用函数式接口之Supplier
  • Supplier接口
    Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。
  • 常用方法
    只有一个无参的方法
    [td]
    方法名
    说明
    T get()
    按照某种实现逻辑(由Lambda表达式实现)返回一个数据

常用函数式接口之Consumer
  • Consumer接口
    Consumer<T>接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
  • 常用方法
    Consumer<T>:包含两个方法
    [td]
    方法名
    说明
    void  accept(T t)对给定的参数执行此操作
    default Consumer<T>          andThen(Consumer after)返回一个组合的Consumer,依次执行此操作,然后执行 after操作

常用函数式接口之Predicate
  • Predicate接口,判断用(返回布尔值)
    Predicate<T>接口通常用于判断参数是否满足指定的条件
  • 常用方法
    [td]
    方法名
    说明
    boolean test(T t)对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
    default Predicate<T> negate()返回一个逻辑的否定,对应逻辑非
    default Predicate<T> and(Predicate other)返回一个组合判断,对应短路与
    default Predicate<T> or(Predicate other)返回一个组合判断,对应短路或

常用函数式接口之Function
  • Function接口
    Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
  • 常用方法
    [td]
    方法名
    说明
    R  apply(T t)将此函数应用于给定的参数
    default <V> Function andThen(Function after)返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果

Strem流
Stream流把真正的函数式编程风格引入到Java中
Stream应用于集合、数组。
生成Stream流的方式
  • Collection体系集合
    使用默认方法stream()生成流, default Stream<E> stream()
    list.stream()    set.stream()     数组生成流:Stream.of()
  • Map体系集合
    把Map转成Set集合,间接的生成流
  • 数组
    通过Stream接口的静态方法of(T... values)生成流

Stream流中间操作方法
  • 概念
    中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。
  • 常见方法
    [td]
    方法名
    说明
    Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
    Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
    Stream<T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
    static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
    Stream<T> distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流,去重
    Stream<T> sorted()返回由此流的元素组成的流,根据自然顺序排序
    Stream<T> sorted(Comparator comparator)返回由该流的元素组成的流,根据提供的Comparator进行排序
    <R> Stream<R> map(Function mapper)返回由给定函数应用于此流的元素的结果组成的流,输入一个值返回一个值
    IntStream mapToInt(ToIntFunction mapper)返回一个IntStream其中包含将给定函数应用于此流的元素的结果,可结合sum、max、min方法使用

Stream流终结操作方法
  • 概念
    终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。
  • 常见方法
    [td]
    方法名
    说明
    void forEach(Consumer action)对此流的每个元素执行操作
    long count()返回此流中的元素数

Stream流的收集操作
  • 概念
    对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。
  • 常用方法
    [td]
    方法名
    说明
    R collect(Collector collector)把结果收集到集合中
  • listStream.collect(Collectors.toList())将流存到list集合中
  • setStream.collect(Collectors.toSet());将流存到Set集合中
  • mapStream.collect(Collectors.toMap(key,value))将流存到Map集合中
  • 工具类Collectors提供了具体的收集方式
    [td]
    方法名
    说明
    public static <T> Collector toList()把元素收集到List集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static  Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

十五、类加载、反射、模块化类加载
  • java虚拟机类加载的过程和时机

    • 类加载

      • 内置的类加载器,将class文件加载入虚拟机内存
      • 为当前class文件生成java.lang.Class对象(创建对象的模板,分析类的属性方法)

    • 类链接

      • 验证:验证当前类的语法结构
      • 准备:   类变量的内存分配
      • 解析:    将变量名换成内存地址

    • 类初始化

      • 初始化:  变量进行初始化


  • 何时会触发类的加载和初始化

    • java命令执行相应的class 文件的时候
    • 创建类的对象    new Person()
    • 调用类的静态方法或静态变量  Person.name    Person.eat()
    • 初始化某个类的子类
    • 通过反射机制获取java.lang.Class对象的时候

  • 类加载器的作用

    • 将class文件加载入内存,为class文件生成 java.lang.Class对象

  • Java类加载器分类(父类委托)

    • 应用程序类加载器:负责加载我们工程中自定义的类
    • 平台类加载器:底层类库的加载
    • 根类加载器:底层类库的加载


反射
作用:反射被称为框架技术的灵魂;
  • 反射的概念

    • 概念:通过class对象动态的获取类内部结构(构造函数,方法,变量),对其进行调用的过程

  • 获取类class对象的三种方式

    • 类名.class
    • 对象.getClass()
    • Class.forName("全类名,包名加类名")

  • 反射获取构造方法

    • 获取共有构造方法: c.getConstructors()
    • 获取全部构造方法: c.getDeclaredConstructors()
    • 获取单个的共有构造方法: c.getConstructor(Class<?>... parameterTypes)
    • 获取单个全部的构造方法:c.getDeclaredConstructor(Class<?>... parameterTypes)
    • 获取到构造方法对应的对象后如何实例化:newInstance()
    • 可以调用私有构造:setAccessible(true);

  • 反射获取字段

    • 获取所有公有属性:getFields()
    • 获取所有属性:getDeclaredFields()
    • 获取单个公有属性:getField(String fieldName)
    • 获取单个所有属性:getDeclaredField(String fieldName)
    • 为属性赋值:变量名.set(obj,"西安");
    • 读取属性的值:get(obj)

  • 反射调用方法

    • 获取所有公有方法包括继承来的:getMethods()
    • 获取所有方法不包括继承来的:getDeclaredMethods()
    • 获取单个公有方法:getMethod("方法名")
    • 获取单个方法:getDeclaredMethod("方法名")
    • 方法调用:m.invoke(obj);


模块化
  • 模块化编程

    import com.test.MyInterface;
    import com.test.MyInterfaceImpl1;
    import com.test.MyInterfaceImpl2;

    module MyOne {
        exports com.test;
        provides MyInterface with MyInterfaceImpl1, MyInterfaceImpl2;
    }
    import com.test.MyInterface;

    module MyTow {
        requires MyOne;
        uses MyInterface;
    }
使模块a中的类可以创建模块b中类的对象并使用,
在被调用的模块内创建module-info.java
file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\05.png?lastModify=1558231862
在要调用的模块创建module-info.java,并写入以下内容
file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\06.png?lastModify=1558231862
模块的基本使用
  • 在项目中创建两个模块。一个是myOne,一个是myTwo
  • 在myOne模块中创建以下包和以下类,并在类中添加方法
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\01.png?lastModify=1558231862
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\02.png?lastModify=1558231862
  • 在myTwo模块中创建以下包和以下类,并在类中创建对象并使用
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\03.png?lastModify=1558231862
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\04.png?lastModify=1558231862
  • 在myOne模块中src目录下,创建module-info.java,并写入以下内容
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\05.png?lastModify=1558231862
  • 在myTwo模块中src目录下,创建module-info.java,并写入以下内容
    file://H:\%E5%B0%B1%E4%B8%9A%E7%8F%AD1\%E5%B0%B1%E4%B8%9A%E7%8F%ADse\day15-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&%E5%8F%8D%E5%B0%84&%E6%A8%A1%E5%9D%97%E5%8C%96\%E7%AC%94%E8%AE%B0\img\06.png?lastModify=1558231862

十六、Junit测试
1.测试分类
  • 黑盒测试:傻瓜式测试。只关心结果!
  • 白盒测试:更有技术含量。除了关心结果,还要关心程序的安全性和健壮性

2.Junit基本使用
  • 在方法声明上,加上@Test注解
  • 示例代码


public class Calculator {

    /**
     * 加法
     * @param a
     * @param b
     * @return
     */
    public int add (int a , int b){
        //int i = 3/0;
        return a - b;
    }

    /**
     * 减法
     * @param a
     * @param b
     * @return
     */
    public int sub (int a , int b){
        return a - b;
    }

}public class CalculatorTest {
    /**
     * 初始化方法:
     *  用于资源申请,所有测试方法在执行之前都会先执行该方法
     */
    @Before
    public void init(){
        System.out.println("init...");
    }

    /**
     * 释放资源方法:
     *  在所有测试方法执行完后,都会自动执行该方法
     */
    @After
    public void close(){
        System.out.println("close...");
    }

    /**
     * 测试add方法
     */
    @Test
    public void testAdd(){
        //1.创建计算器对象
        System.out.println("testAdd...");
        Calculator c  = new Calculator();
        //2.调用add方法
        int result = c.add(1, 2);
        //3.断言  我断言这个结果是3
        Assert.assertEquals(3,result);
    }

    @Test
    public void testSub(){
        //1.创建计算器对象
        Calculator c  = new Calculator();
        int result = c.sub(1, 2);
        System.out.println("testSub....");
        Assert.assertEquals(-1,result);
    }
}
3.单元测试需要使用的注解
  • @Before    执行功能方法之前被执行
  • @Test         执行功能方法
  • @After       执行功能方法之后被执行

十七、注解注解概念
  • 注解就是用于说明程序的。参与程序的运行
  • JDK1.5版本之后的新特性

注解的作用
  • 编写文档(API帮助文档)
  • 编译检查(@Override   @FunctionalInterface)
  • 代码分析(配合反射使用)【重点

常用的注解
  • @Override     用于检测方法是否是重写的
  • @Deprecated    用于标识某个方法是否已过时
  • @SuppressWarnings    用于压制警告
  • @FunctionalInterface    用于检测接口是否是一个函数式接口
  • @Before      在功能方法之前被执行
  • @Test           执行功能方法
  • @After         在功能方法之后被执行

自定义注解
  • 格式


public @interface 注解名称{
   
}
  • 本质

    • 注解本质就是一个接口!所有的注解都实现了Annotation接口

  • 注解中的属性

    • 属性(方法)的返回值数据类型

      • 基本数据类型四类八种
      • String
      • 枚举
      • 注解
      • 以上数据类型的数组

    • 注意事项

      • 可以使用default给属性设置一个默认初始化值
      • 如果属性名叫value,而且只有一个属性时,那么赋值时,属性名可以省略
      • 数组进行赋值时,需要使用{}。如果数组中只有一个值,{}可以省略


  • 元注解

    • @Target(ElementType)自定义注解作用的位置

      • TYPE   用于类上面
      • METHOD  用于方法上面
      • FIELD     用于变量上面

    • @Retention(RetentionPolicy)一般用RUNTIME

      • SOURCE   源代码阶段
      • CLASS      字节码阶段
      • RUNTIME  运行时阶段

    • @Documented     可以被抽取到帮助文档中
    • @Inherited            可以被子类继承


解析注解
  • 狗类


public class Dog {
    public void eat() {
        System.out.println("狗吃肉");
    }
}
  • 猫类


public class Cat {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
  • 注解

@Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AnimalAnnotation {
    String className();   // 记录 全类名
    String methodName();  // 记录 方法名
}
  • 测试类


@AnimalAnnotation(className = "com.itheima01.Cat",methodName = "eat")
public class Test06 {
    public static void main(String[] args) throws Exception{
        //获取注解中的属性值
        //1.获取Test06类的Class对象
        Class<Test06> cls = Test06.class;
        //2.通过Class对象来获取注解对象
        AnimalAnnotation animal = cls.getAnnotation(AnimalAnnotation.class);
        //3.通过注解对象调用属性。来获取属性值
        String className = animal.className();
        String methodName = animal.methodName();


        //通过反射来调用方法
        //1.获取Class对象
        Class cls2 = Class.forName(className);
        //2.获取方法
        Method method = cls2.getMethod(methodName);
        //3.执行方法
        method.invoke(cls2.newInstance());
    }
}



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马