Java8新特性
    java8 就是JDK8,这个版本,目前是国内市场主流的一个开发版本。它支持函数式编程,新的Javascript引擎,新的日期类,新的Stream API。

    1. lambda表达式:允许把函数作为一个方法的参数(把函数传递进方法)
    2. 方法引用:可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使代码看起来更加的简洁,减少冗余代码。
    3. 默认方法:default关键字修饰方法,在接口里边定义一个方法,包含方法体,所有实现或者继承这个接口的类或接口,都拥有了这个方法,并且可以直接调用。
    4. Stream API。可以理解为一个集合或者数组的流水线操作。
    5. Date Time API新的日期时间类。比之前咱们学的安全,好用。
    6. OPtional类 解决空指针异常
    7. Nashorn和javascript引擎。

    第一章:lambda表达式
    1.1【掌握】lambda表达式的概念
    lambda表达式可以看成是一个匿名内部类,允许把函数作为一个方法的参数,将代码想参数一样进行传递,使用lambda表达式,可以使得代码更加简洁。

    <函数式接口> <变量名>=(参数1,参数2,….)->{
    // 方法体
    }
    这里是一个减号和大于号,注意:与ES6(js的常用版本)里边的lambda表达式有区别,那里是”=>”。

    1.2【掌握】认识lambda表达式之后,那么为什么要使用这个lambda表达式呢?

    1. 因为简单,简洁。可以实现多个策略的模式,很多可以实现简单操作处理。

    案例需求:假如现在有个大王,要从100个人中选出几个美女作为压寨夫人的候选人。要根据大王条件来选。
    案例:

    package com.qianfeng.java8.monday.lambda.demo;
    import java.util.ArrayList;
    import java.util.List;
    /**
    * 作者:黎杭
    * 日期:2020/2/17
    *


    * 模拟大王选压寨夫人的代码
    */
    public class Test {
    public static void main(String[] args) {
    // 第一步,先创建一百个人,不管男女,随机创建
    List list = new ArrayList<>();// 这个集合拿来装这一百个候选人
    for (int x = 0; x < 100; x++) {
    String sex = Math.ran
    dom() < 0.5 ? “女” : “男”;// 随机取小于0.5就是女,否则是男
    User user = new User(“竞选人” + x, 60 + x, 10.0 + x, x, sex);// crtl+q提示参数
    list.add(user);
    }
    System.err.println(list);
    // 大王要求1:把年龄 16岁到26岁之间的女娃娃给我找出来!
    List users = _findUse_rsByCondition(list);// 选出符合大
    王口味的人
    System.err.println(users);
    // 大王要求2:这次年龄扩大到14岁到30岁女生都行
    List users2 = findUsersByCondition2(list);// 选出
    符合大王口味的人
    System.err.println(users2);
    // 大王又说了,不行,这次我不仅要选女的,男的也给我找回来,找回来给我搬砖
    // 这个时候就会发现一个问题,客户的需求总是在变化,每变化一
    次,我们就要修改方法,或者新增代码
    }
    public static List findUsersBy_Condition(List list) {// 将l_ist作为参数传入,list是所有候选人
    List resList = new ArrayList<>();// 先准备一个结果集,符合条件的人,就放到这个集合里边,等下返回
    for
    (User u : list) {
    if (16 < u.getAge() // 如果是大于16岁,成年了
    && u.getAge() < 26 // 小
    于26岁,非常青春
    && “女”.equals(u.ge_tSex())) {// 是女娃娃
    resList.add(u);/_/ 把当前这个符合条件的女娃娃放到结
    果集里边
    }
    }
    retu
    rn resList;// 返回所有符合条件的人,给大王
    }

    public static List _findUsersByCondition2(List _list) {// 将list作为参数传入
    ,list是所有候选人
    List resList = new ArrayList<>();
    // 先准备一个结果集,符合条件的人,就放到这个集合里边,等下返回
    for (User u : list) {
    if (14 < u.ge_tAge() // 如果是大于16岁,成年了
    && u.get_Age
    () < 30 // 小于26岁,非常青春
    && “女”.equals(u.getSex())) {// 是女娃娃
    _ resL_ist.add(u);// 把当前这
    个符合条件的女**娃娃放到结果集里
    }
    }
    return resList;// 返回所有符合条件的人,给大王
    }
    }

    User类

    package com.qianfeng.java8.monday.lambda.demo;


    import java.io.Serializable;

    /**
    * 作者:黎杭
    * 日期:2020/2/17
    *


    * 一个User对象类,表示所有人
    */

    public class User implements Serializable {
    private String name;// 名
    private Integer height;// 身高
    private Double weight;// 体重
    private Integer age;// 年龄
    private String sex;// 性别
    public User(String name, Integer height, Double weight, Integer age, String sex) {
    this.name = name;
    this.height = height;
    this.weight = weight;
    this.age = age;
    this.sex = sex;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public Integer getHeight() {
    return height;
    }
    public void setHeight(Integer height) {
    this.height = height;
    }
    public Double getWeight() {
    return weight;

    public void setWeight(Double weight) {
    this.weight = weight;
    }
    public Integer getAge() {
    return age;
    }
    public void setAge(Integer age) {
    this.age = age;
    }
    public String getSex() {
    return sex;
    }
    public void setSex(String sex) {
    this.sex = sex;
    }
    }

    案例升级版:

    package com.qianfeng.java8.monday.lambda.demo1;


    import com.qianfeng.java8.monday.lambda.demo.User;

    import java.util.ArrayList;
    import java.util.List;

    /**
    * 作者:黎杭
    * 日期:2020/2/17
    *


    * 模拟大王选压寨夫人的代码
    */
    public class Test1 {
    public static void main(String[] args) {
    // 第一步,先创建一百个人,不管男女,随机创建
    List<User> list = new ArrayList<>();// 这个集合拿来装这一个候选人

    for (int x = 0; x < 100; x++) {
    Stri_ng sex = Math.random() < 0.5 ? “女” : “男”;// 随机取小于0.5就是女,否则是男
    User user = new User(“竞选人” + x, 60 + _x, 10.0 + x, x, sex);// c_rtl+q提示参数
    list.add(user);
    }
    System.er_r.println(list);

    // 大王要求1:把年龄 16岁到26岁之间的女娃娃给我找出来!
    List us_ers = findUsersByCondit_ion(list, new FindGir_l());// 选出符合大王口味的人
    System._err.println(users);

    // 大王要求_2:这次年龄扩大到14岁到30岁女生都行
    List users1 = findUsersByCond_ition(list, new FindGirl1());// 选出符合大王口味的人,第二次
    System.err.println(users1);
    // 大王又说了,不行,这次我需要男的给我找回来,找回来给我搬砖
    // 这个时候就会发现一个问题,客户的需求总是在变化,每变化一次,我们就要修改方法,或者新增代码
    List users2 = findUsers_ByCondition(list, new Fin_dMan());// 选出符合大王口味的人,第二次
    S_ystem.err.println(users2);

    // 注意观察,只需要修改方法参数即可,并且在修改具体实现类的test(检测)方法即可
    }
    public static List findUsersByCondition(List list, Condition condition) {// 将list作为参数传入,list是所有候选人
    L_ist resList = new ArrayList<>();//
    先准备一个结果集,符合条件的人,就放到这个集合里边,等下返回
    for (User u : list) {
    if (condition.test(u)) {// 等待外界传来条件,只要符合条件,就加入到结果集里边
    resList.a_dd(u);// 把当前这个符合条件的女娃娃放到结果集里边
    }
    }_
    return resList;// 返回所有符合条件的人,给大王
    }
    }

    插入条件接口子类:

    public interface Condition {
    boolean test(V v);// 检测符不符合条
    }
    public class FindGirl implements Condition {
    @Override
    public boolean test(User user) {
    return user.getAge() < 26 && 16 < user.getAge() && “女”.equals(user.getSex());// 这个就是大王的第一次提的要求
    }
    }
    public class FindMan implements Condition {
    @Override
    public boolean test(User user) {
    return user.getAge() < 30 && 14 < user.getAge() && “男”.equals(user.getSex());// 这个就是大王的第一次提的要求
    }
    }

    使用lambda表达式之后代码实例:

    public class Test1 {
    public static void main(String[] args) {
    // 第一步,先创建一百个人,不管男女,随机创建
    List list = new ArrayList<>();// 这个集合拿来装这一百个候选人

    for (int x = 0; x < 100; x++) {
    String sex = Math._random() < 0.5 ? “女” : “男”;// 随机取小于0.5就是女,否则是男
    User user = new User(“竞选人” + x, 60 + x, 10.0 + x, x, sex);// crtl+q提示参数
    list.add(user);
    }
    System.err.println(list
    );
    // 大王要求1:把年龄 16岁到26岁之间的女娃娃给我找出来!
    // 由于学了lambda表达式,所以这个匿名内部类,就可以简写// 这个就是大王的第一次提的要求
    // 直接创建一个匿名内部类
    List<_User> users = findUs_ersByCondition(list, user -> user.getAge() < 26 && 16 < user.getAge() && “女”.equals(us_er.getSex()));// 选出符合
    大王口味的人
    System.err.println(users);
    // 大王要求2:这次年龄扩大到14岁到30岁女生都行
    List users1 = fin_dUsersByCondition(list, user -> user.getAge() < 30 && 14 < user.getAge() && “女”.equals(user.getSex()));// 选出符合大王口味的人,第二次
    System.err.printl_n(users1);

    // 大王又说了,不行,这次我需要男的给我找回来,找回来给我搬砖
    // 这个时候就会发现一个问题,客户的需求总是在变化,每变化一次,我们就要修改方法,或者新增代码
    List users2 = findUsersByCondition(list, user -> user.getAge() < 30 && 14 < user.getAge() && “男”.equals(user.getSex()));// 选出符合大王口味的人,第二次
    System.err.println(users2);
    // 注意观察,只需要修改方法参数即可,并且在修改具体实现类的test(检测)方法即可
    }
    public static List findUsersByCondition(List list, Condition condition) {// 将list作为参数传入,list是所有候选人
    List resList = new ArrayList<>();// 先准备一个结果集,符合条件的人,就放到这个集合里边,等下返回
    for (User u : list) {
    if (condition.test(u)) {// 等待外界传来条件,只要符合条件,就加入到结果集里边
    resList.add(u);// 把当前这个符合条件的女娃娃放到结果集里边
    }
    }
    _ retu_rn resList;// 返回所有符合条件的人,给大王
    }
    }

    1.3【掌握】使用lambda表达式注意事项
    首先:语法要注意:()->{},左边部分(括号内)就是参数,花括号{}内就是方法主体

    1. 形参列表的数据类型会自动推算。
    2. 如果一个参数都没有,那么只需要保留一个空括号即可“()
    3. 如果参数只有一个,那么这个括号可以省略,只需要写参数名称即可。
    4. 如果执行语句只有一句,并且没有返回值,那么花括号可以省略。如果有返回值,必须同时省略return关键字
    5. lambda表达式虽然是一个匿名内部类,但是不会生成单独的一个文件
    6. lambda表示若访问了局部变量, 则局部变量必须是final的,若没有加final关键字,系统会自动添加.(等下演示)

    1.4【掌握】函数式接口
    如果一个接口有且只有一个抽象方法,则该接口就可以称之为函数式接口。
    案例:判断一个接口是否是函数式接口

    @FunctionalInterface // 如果不是函数式接口的时候,那么会报错的,所以大家以后如果要写一个函数式接口,那么请加上@FunctionalInterface注解
    public interface Condition {
    boolean test(V v);// 检测符不符合条件
    default String test2() {// 这个不是抽象方法
    return “”;
    }
    }

    函数式的接口就可以使用lambda表达式,由于有且只有一个抽象方法,所以lambda表达式的方法体就会被看成是这个抽象方法唯一的实现。说的再直接点就是这个方法主体代码,就是唯一的那个抽象方法的实现。
    java为了程序员开发方便,提供一些内置的函数式接口,供程序员使用。

    函数式接口 参数类型 返回类型 描述
    public interface Consumer T void 对给定的参数执行此操作。将传递进来的参数作为消费处理。这种接口就把它当作一个参数传递就行了。
    public interface Supplier 无参 T T get();返回类型为T的实例
    public interface Function T R R apply(T t);将入参进行应用操作,得到R类型的返回值
    public interface Predicate T boolean boolean test(T t);检测类型t是否满足某些条件,满足则返回true,不满足返回false

    供给型接口:

    public class TestSupplier2 {
    public static void main(String[] args) {
    // Suibian sup = () -> (int) (Math.random() * 100);
    // (int) (Math.random() * 100) 实际上是一个实例,它只是简写了!
    // 以下是完整的写法
    // Suibian sup2 = new Suibian() {
    // @Override
    // public Integer getNum() {
    // return (int) (Math.random() * 100);
    // }
    // };
    List numbers = getNumbers(() -> (int) (_Math.random() 100));
    *
    System.err.println(number_s);

    }
    // Suibian 只是用来接收实现类的 作用而已,它实际上没有什么意义
    public static List getNumbers(Suibian<_Integer> sup) {// sup代表的不是接口,是匿名实现类的实例,
    List<Integer> list = new ArrayList<>();
    Integer _i = sup.getNum();// get方法就是调用了 (int) (Math.random()
    100)代码
    li*st.add(
    i);
    return list;
    }
    }

    传统方式代码:

    public class Test {
    public static void main(String[] args) {

    Function f = new FuncImpl();
    String string = getSt_ring(789, f);
    System.err.println(string);

    }
    // 传统方式都能看懂
    public static String getString(Integer i, Function f) {


    // Integer integer = 99;// 先定义一个 整数数字
    String res = f.apply(i);// 调用apply 实际上是调用 覆写方法中的主体代码:return String.valueOf(integer);
    return res;
    }
    }
    public class Test2 {
    public static void main(String[] args) {
    // 把传进来的参数 数字变成字符串返回
    Function f = integer -> integer + “”;// 极简风格
    String string = getSt_ring(999, f);
    System.err.println(string);
    }
    // 传统方式都能看懂
    public static String getString(Integer i, Function f) {

    // Integer integer = 99;// 先定义一个 整数数
    String res = f.apply(i);// 调用apply 实际上是调用 覆写方法中的主体代码:return String.valueOf(integer);
    return res;
    }
    }

    断言型函数式接口:

    public class Test {
    public static void main(String[] args) {
    Predicate p = new FindGirl();
    boolean b = te_st1(p);
    System.err.println(b);
    }

    public static boolean test1(Predicate p) {
    User u = new User(“张三”, 170, 45.0, 22, “女”);
    boolean test = p
    .test(u);// 检测的结_

    return test;
    }
    }
    public class FindGirl implements Predicate {
    @Override
    public boolean test(User user) {
    return 16 < user.getAge() && 30 > user.getAge() && “女”.equals(user.getSex());// 认为合格
    }
    }

    匿名内部类来实现:

    public class Test2 {
    public static void main(String[] args) {
    Predicate p = new Predicate() {
    @Override
    public boolean test(User user) {
    return 16 < user.getAge() && 30 > user.getAge() && “女”.equals(user.getSex());// 认为合格
    }
    };// 匿名内部类实现
    boolean b = test1(p);
    System.err.println(b);
    }
    public static boolean test1(Predicate p) {
    User u = new User(“张三”, 170, 45.0, 22, “女”);
    boolean test = p.test(u);// 检测的结果
    return test;
    }
    }

    lambda表达式来实现:

    public class Test3 {
    public static void main(String[] args) {
    // 认为合格
    Predicate p = user -> 16 < user.getAge() && 30 > user.getAge() && “女”.equals(user.getSex());// 匿名内部类实现
    boolean b = t_est1(p);
    System.err.println(b);
    }
    public static boolean test1(Predicate p) {
    User u = new User(“张三”, 170, 45.0, 22, “女”);
    boolean test = p
    .test(u);// 检测的结_
    return test;
    }
    }

    第二章:【掌握】方法引用
    方法引用是lambda表达式的更简洁的写法。使用的时候有条件:如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
    方法引用的语法:

    1. 对象::实例方法
    2. 类名::静态方法
    3. 类名::实例方法
    4. 类名::new

    对象::实例方法的代码示例

    public class Test {
    public static void main(String[] args) {
    // 先来一个消费型的函数式接口
    Consumer consumer = s -> System.err.println(s);
    Consumer consumer1 = System.err::println;// 这个就是对上面lambda表达式的更加简洁的写法
    consumer.accept(“你好”);
    consumer1.accept(“你好2”);
    }
    }

    类名::静态方法名 lambda表达式代码:

    public class Test2 {
    public static void main(String[] args) {
    // 先来一个消费型的函数式接口
    Comparator comparator = (o1, o2) -> Integer.comp_are(o1, o2);
    Comparator comparator2 = Integ_er::com_p_are;// 继续用类名::静态方法名称


    int compare = comparator.compare(88, 88);// 第1种方法测试
    System.err.println(compare);

    int compare1 = comparator2.compare(88, 88);// 第2种方法测
    System.err.println(compare1);

    }
    }

    实例名称::方法名称

    public class Test3 {
    public static void main(String[] args) {
    User user = new User(“李四”, 180, 60.0, 25, “男”);
    Supplier sup = user::getName;// 这个就是对象::方法名称的使用
    String name = sup.get();// 等同于 user.getName()方法了
    System.err.println(“输出名字为:” + name);
    }
    }

    对象::new

    public class Test4 {
    public static void main(String[] args) {
    Supplier sup = () -> new User(“李四”, 180, 60.0, 25, “男”);
    Supplier sup2 = User::new;// 这种方法只能够用于无参构造
    }
    }

    第三章:【掌握】Stream API
    待补充。。。。