JDK8的新特性

1.lambda表达式

概念:

Lambda表达式:特殊的匿名内部类,语法更简洁。

Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据 一样传递。

语法:

<函数式接口> <变量名> = (参数1,参数2...)->{

                        //方法体

};

代码:

public class My implements Runnable{
    @Override
    public void run() {
        System.out.println("这是自定义任务接口类");
    }
}

测试:

public class Test01 {
    public static void main(String[] args) {
        My m1 = new My();
        Thread t1 = new Thread(m1);
        t1.start();

        //匿名内部类
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("这是匿名内部类方式的任务对象");
            }
        };
        Thread t2 = new Thread(r);
        t2.start();

    }
}

1.Thread类需要 Runnable接口作为参数,而其中抽象的run 方法是用来指定线程核心任务内容

2. Runnable接口的实现类,重写run方法

3.实现Runnable接口的实现类,使用匿名内部类。

4.必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错

 //lambda表达式
        Runnable r1 = ()->{
            System.out.println("这是使用lambda表达式完成的");
        };
        Thread t3 = new Thread(r1);
        t3.start();

1.2无参无返回值

函数式接口:

@FunctionalInterface
 interface Swimming {
    public void Swimming(String name);
}

 测试:

public class Test01 {
    public static void main(String[] args) {
        //匿名内部类
        /*Swimming s = new Swimming() {
            @Override
            public void Swimming() {
                System.out.println("这是使用匿名内部类的方式");
            }
        };
        fun(s);*/

        //lambda表达式
        Swimming swimming = n-> System.out.println("这是lambda表达式");

        fun(n->{
            System.out.println("这是lambda表达式 "+n);
        });
    }
    public static void fun(Swimming s){
        s.Swimming("张三");
    }
}

 1.3有参数有返回值的Lambda

public abstract int compare(T o1, T o2);

当需要对一个对象集合进行排序时, Collections.sort 方法需要一个 Comparator 接口实例来指定排序的规则。

public class Person {
    private String name;
    private int age;
    private int height;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }

    public Person(String name, int age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}
public class Test01 {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("张三",18,188));
        personList.add(new Person("李四",23,180));
        personList.add(new Person("王五",53,182));
        personList.add(new Person("赵六",34,183));
        personList.add(new Person("孙琦",32,186));
        //对集合中的元素进行排序,按照年龄从小到大。
        //传统做法:Comparator:排序规则接口。
        Comparator<Person> comparator = (o1, o2)-> o1.getAge()- o2.getAge();
        //int:0表示新加的元素和集合中原来的比对的相同
        //1:o2比o1小
        //-1:o2比o1大
        Collections.sort(personList,comparator);
        for (Person p:personList){
            System.out.println(p);
        }
    }
}

1.4详细介绍lambda表达式

Lambda引入了新的操作符:->(箭头操作符),->将表达式分为两部分

1.左侧:(参数1,参数2...)表示参数列表

2.右侧:{}内部是方法体

3.如果形参只有一个,()可以省略,只需要参数的名称即可

4.如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时 省略return,且执行语句也保证只有一句

5.Lambda不会生成一个单独的内部类文件

2.函数式接口

1.如果一个接口只有一个抽象方法,称其为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。

2.@Functionallnterface注解检测接口是否符合函数式接口。

内置函数式接口的由来:

interface Operater {
    public abstract void getSum(int [] array);
}
public class Test01 {
    public static void main(String[] args) {
        Operater o = array -> {
          int sum = 0;
            for (int i : array) {
                sum+=i;
            }
            System.out.println("数组的总和是:"+sum);
        };
        fun(o);
    }
    public static void fun(Operater operater){
        int [] array = {1,3,5,7,9};
        operater.getSum(array);
    }
}

常见得函数式接口:

2.1Consumer<T>

有参数,无返回值:

//Consumer<T> 消费性函数式接口
public class Test01 {
    public static void main(String[] args) {
        Consumer<Double> consumer = t->{
            System.out.println("充值了"+t+"话费");
        };
        fun(consumer,100);
    }

    //调用某个方法时,该方法需要的参数为接口类型,这时就应该能想到使用lambda
    public static void fun(Consumer<Double> consumer,double money){
        consumer.accept(money);
    }
}

2.2Supplier<T>供给型函数式接口

无参,想有返回结果的函数式接口时:T:表示返回结果的泛型

//Supplier<T> 供给型函数式接口
public class Test02 {
    public static void main(String[] args) {
        fun(()->new Random().nextInt(10));
    }

    public static void fun (Supplier<Integer> supplier){
        Integer integer = supplier.get();
        System.out.println("内容为:"+integer);
    }
}

2.3Function<T,R> 函数型函数式接口

T: 参数类型的泛型,R: 函数返回结果的泛型

有参,有返回 值时:

例子: 传入一个字符串把小写转换为大写。

//Function<T,R> 函数型函数式接口
public class Test03 {
    public static void main(String[] args) {
        fun((t)->{return t.toUpperCase();},"my");
    }

    public static void fun(Function<String,String> function,String msg){
        String apply = function.apply(msg);
        System.out.println("内容为:"+apply);
    }
}

 2.4Predicated<T>

T: 参数的泛型,boolean test(T t);

当传入一个参数时,需要对该参数进行判断时,则需要这种函数:

public class Test05 {
    public static void main(String[] args) {
        fun((n)->{return n.length()>3?true:false;},"迪丽热巴");
    }
    public static void fun(Predicate<String> predicate,String name){
        boolean test = predicate.test(name);
        System.out.println("该名称的长度是否长呀:"+test);
    }
}

3.方法引用

3.1lambda表达式的冗余

public class Test06 {
    public static void main(String[] args) {
        /*fun(array->{int sum=0;
            for (Integer i : array) {
                sum+=i;
            }
            System.out.println("数组的长度为:"+sum);
        });*/
        /*fun(array->Test06.sum(array));*/
        fun(Test06::sum);
    }
    public static void fun(Consumer<Integer[]> consumer){
        Integer[] array = {1,3,5,7,9};
        consumer.accept(array);
    }
    public static void sum(Integer[] array){
        int sum = 0;
        for (Integer i : array) {
            sum+=i;
        }
        System.out.println("数组的和为:"+sum);
    }
}

3.2什么是方法引用

方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。

方法引用的分类:

3.3静态方法引用和实例方法引用

public class People {
    private String name;
    private int age;

    public static int compareTo(People p1,People p2){
        return p1.getAge()-p2.getAge();
    }

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
public class Test01 {
    public static void main(String[] args) {
        //静态方法的使用
        People[] p = {new People("张三",15),new People("李四",18),new People("王五",20)};
        //Comparator<People> c = (o1,o2)-> o1.getAge()- o2.getAge();
        //Comparator<People> c = (o1,o2)-> People.compareTo(o1,o2);
        Comparator<People> c = People::compareTo;
        Arrays.sort(p,c);

        //实例方法的使用
        /*People p = new People("张三",20);
        //Supplier<String> s = ()->p.getName();
        Supplier<String> s =p::getName;
        fun(s);*/
    }
    public static void fun(Supplier<String> supplier){
        String s = supplier.get();
        System.out.println("结果为:"+s);
    }
}

3.4对象方法引用和构造方法引用

public class People {
    private String name;

    public People() {
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                '}';
    }

    public People(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Test01 {
    public static void main(String[] args) {
        //3.对象方法引用: 类名::实例方法.    (参数1,参数2)->参数1.实例方法(参数2)
       /* Function<String,Integer> function = (str)->{
            return str.length();
        };*/
        Function<String,Integer> function = String::length;
        Integer hello = function.apply("hello");
        System.out.println(hello);

        //比较两个字符串的内容是否一致.T, U, R
        // R apply(T t, U u);
        /*BiFunction<String,String,Boolean> bi = (t,u)->{
            return t.equals(u);
        };*/
        BiFunction<String,String,Boolean> bi =String::equals;
        Boolean apply = bi.apply("hello", "world");
        System.out.println(apply);

        // 4.构造方法引用: 类名::new         (参数)->new 类名(参数)
           /*Supplier<String> supplier=()->{
                return new String("hello");
           };
         Supplier<People> supplier=People::new;*/
        Function<String,People> function1 = People::new;
        People people = function1.apply("张三");
        System.out.println(people);
    }
}

4.Stream流

Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作.

4.1为什么使用Stream流

集合操作数据不好的一面,很繁琐。

public class My {
    public static void main(String[] args) {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 1.拿到所有姓张的
        ArrayList<String> zhangList = new ArrayList<>(); // {"张无忌", "张强", "张三丰"}
        for (String name : list) {
            if (name.startsWith("张")) {
                zhangList.add(name);
            }
        }
// 2.拿到名字长度为3个字的
        ArrayList<String> threeList = new ArrayList<>(); // {"张无忌", "张三丰"}
        for (String name : zhangList) {
            if (name.length() == 3) {
                threeList.add(name);
            }
        }
// 3.打印这些数据
        for (String name : threeList) {
            System.out.println(name);
        }
    }
}

Stream流中对于集合的操作语法更加简洁:性能比传统快。

public class Test01 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰","赵四");
        list.stream()
                .filter(item->item.startsWith("张"))
                .filter(item->item.length()==3)
                .forEach(item-> System.out.println(item));

        list.stream()
                .filter(i->i.startsWith("赵"))
                .filter(i->i.length()==2)
                .forEach(System.out::println);
    }
}

 4.2Stream流的原理

Stream流不是一种数据结构也不保存数据,而是对数据进行加工处理。Stream可以当做一步一步的流程。在流程上,经过很多个工序使得一个原材料加工成一个商品。

4.3如何获取Stream流对象

public class Test02 {
    public static void main(String[] args) {
        //实例方法引用:(参数)->对象.实例方法(参数)   对象::实例方法
        //item->System.out.println(item);      System.out::println
        //通过集合对象调用stream()获取流
        List<String> list = new ArrayList<>();
        list.add("king");
        list.add("毛哥");
        list.add("家里的");
        list.add("已输入");
        Stream<String> stream = list.stream();
        stream.forEach(System.out::println);

        //通过Arrays数组工具类获取Stream对象
        int[] i = {1,3,5,7,9};
        IntStream stream1 = Arrays.stream(i);
        stream1.forEach(System.out::println);

        //使用Stream类中of方法
        Stream<String> stream2 = Stream.of("张三", "李四", "王五");
        stream2.forEach(System.out::println);

        //通过IntStream.rangeClosed获取流
        IntStream range = IntStream.rangeClosed(1, 5);
        range.forEach(System.out::println);

        //上面都是获取的串行流。还可以获取并行流。如果流中的数据量足够大,并行流可以加快处速度。
        Stream<String> stringStream = list.parallelStream();
        stringStream.forEach(System.out::println);
    }
}

4.4Stream流中常见的api

中间操作api: 一个操作的中间链,对数据源的数据进行操作。而这种操作的返回类型还是一个Stream对象,只有有了终止操作,才会执行中间链,产生其结果。

终止操作api: 一个终止操作,执行中间操作链,并产生结果,使得中间链的返回类型不再是Stream流对象。

public class Test03 {
    public static void main(String[] args) {
        List<People> personList = new ArrayList<>();
        personList.add(new People("欧阳雪",18,"中国",'F'));
        personList.add(new People("Tom",24,"美国",'M'));
        personList.add(new People("Harley",22,"英国",'F'));
        personList.add(new People("向天笑",20,"中国",'M'));
        personList.add(new People("李康",22,"中国",'M'));
        personList.add(new People("小梅",20,"中国",'F'));
        personList.add(new People("何雪",21,"中国",'F'));
        personList.add(new People("李康",22,"中国",'M'));

        //findFirst allMatch所有的都符合才返回true否则返回false anyMatch有一个符合就为true noneMatch没有一个符合就返回true parallel转为并行流
        /*Optional<People> first = personList.parallelStream()
                .filter(i -> i.getSex() == 'F')
                .findFirst();*/
        boolean l = personList.parallelStream()
                .filter(i -> i.getSex() == 'F')
                .allMatch(i -> i.getAge() > 15);
        System.out.println(l);

        //搜集方法 collect 它属于终止方法
        //年龄大于20且性别为M
        List<People> collect = personList.stream()
                .filter(i -> i.getAge() > 20)
                .filter(i -> i.getSex() == 'M')
                .collect(Collectors.toList());
        System.out.println(collect);

        //求集合中所有人的年龄和,参数和返回类型必须一致
        Optional<Integer> reduce = personList.stream()
                .map(i -> i.getAge())
                .reduce((a, b) -> a + b);
        System.out.println(reduce.get());

        //查找最大年龄的人
        Optional<People> max = personList.stream()
                .max((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println(max.get());

        //查找年龄最小的人
        Optional<People> min = personList.stream()
                .min((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println(min.get());

        //对流中元素排序
        personList.stream()
                .sorted((o1,o2)->o1.getAge()-o2.getAge())
                .forEach(System.out::println);

        //集合中所有元素的名字和年龄
        personList.stream()
                .map(i->{
                        Map<String,Object> m = new HashMap<>();
                        m.put("name",i.getName());
                        m.put("age",i.getAge());
                        return m;})
                .forEach(System.out::println);

        //找到年龄大于20岁的人并输出;filter()过滤器需要一个断言接口函数,断言接口返回true,获取该元素。foreach(Consumer)
        personList.stream()
                .filter(i->i.getAge()>20)
                .forEach(System.out::println);

        //找出所有中国人的数量 count
        long o = personList.stream()
                .filter(i -> i.getCountry().equals("中国"))
                .count();
        System.out.println(o);
    }
}

5.新增了日期时间类

LocalDate: 表示日期类。yyyy-MM-dd

LocalTime: 表示时间类。 HH:mm:ss

LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss zzz

DatetimeFormatter:日期时间格式转换类。

Instant: 时间戳类。

Duration: 用于计算两个日期类

public class Test01 {
    public static void main(String[] args) {
        //LocalDate: 表示日期类。yyyy-MM-dd
        //LocalTime: 表示时间类。 HH:mm:ss
        //LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss.zzz
        //DatetimeFormatter:日期时间格式转换类。
        //Instant: 时间戳类。
        //Duration: 用于计算两个日期类

        LocalDate now = LocalDate.now();//获取当前日期
        LocalDate of = LocalDate.of(2022, 7, 20);//自己指定日期
        System.out.println(now);
        System.out.println(of);

        LocalTime now1 = LocalTime.now();//获取当前时间
        LocalTime of1 = LocalTime.of(21, 32, 56, 60000000);//自己指定时间
        System.out.println(now1);
        System.out.println(of1);

        LocalDateTime now2 = LocalDateTime.now();//获取当前日期时间
        LocalDateTime of2 = LocalDateTime.of(2022, 6, 20, 21, 34,20);//自己指定日期时间

        //计算两个日期相差的天数
        Duration between = Duration.between(of2, now2);
        System.out.println(between.toDays());
        System.out.println(now2);
        System.out.println(of2);

        //把字符串转为日期格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate parse = LocalDate.parse("2022-07-20", dateTimeFormatter);
        //把时间格式转为字符串
        String format = parse.format(dateTimeFormatter);
        System.out.println(format);
        System.out.println(parse);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值