栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

jdk8的新特性

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

jdk8的新特性

1.什么是Lambda表达式

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

2.为什么使用Lambda表达式
匿名内部类
public class Test1 {
    public static void main(String[] args) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("今天你开心了吗?");
            }
        };
        Thread t1=new Thread(runnable);
        t1.start();

    }
    static class fun implements Runnable{
        @Override
        public void run() {
            System.out.println("===========");
        }
    }
}
  • Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心

  • 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类

  • 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类

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

  • 而实际上,似乎只有方法体才是关键所在。

  • 我们可以使用Lambda表达式

3.使用Lambda表达式          1.Lambda表达式的语法

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

                方法体

}

注意: 函数式接口:接口中只有一个抽象方法。

(参数1,参数2): 抽象方法的参数

->: 分隔符

{}:表示抽象方法的实现

        2.Lambda表达式的使用
public class Test {
    public static void main(String[] args) {
        //简化匿名内部类的使用,语法更加简单
        //使用Lambda表达式
        Runnable runnable=()->{
            System.out.println("话梅排骨");
        };
        //创建线程对象
        Thread thread=new Thread(runnable);
        //开启线程
        thread.start();
    }

}
        3.Lamnda表达式可以把函数当做一个方法的参数(函数作为方法参数传递),将代码像数据一样传递
        Thread thread=new Thread(()->{
            System.out.println("话梅排骨");
        });
        //开启线程
        thread.start();
        4.无参无返回值的Lambda表达
 public static void main(String[] args) {
        //使用Lambda表达式
        show(()->{
            System.out.println("我想去游泳");
        });
    }
    //静态方法
    public static void show(swimming s){
        s.swimming();
    }
    //自己定义一个函数式接口
    interface swimming{
        //抽象函数
        public void swimming();
    }
        5.有参有返回值的Lambda

下面举例演示 java.util.Comparator 接口的使用场景代码,其中的抽象方法定义为:

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

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

package guan.demo2;

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


public class Test {
    public  void main(String[] args) {
        //创建集合
        List people=new ArrayList<>();
        //添加数据
        people.add(new Person("李雷",20));
        people.add(new Person("李化",30));
        //对集合中的元素进行排序 按照年龄从大到小。
        //传统做法:Comparator: 排序规则接口
           //int: 0表示新加的元素和集合中原来的比对的相同
        //1: o2比o1小
         //-1: o2比o1大
        Collections.sort(people,(o1,o2)->{
            return o2.getAge()-o1.getAge();
        });
        for (Person p:people) {
            System.out.println(p);
        }
    }
    //定义一个类
    class Person{
        private String name;
        private int age;

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

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

        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;
        }
    }
}
        6.详细介绍Lambda表达式

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

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

                有参:{}内部是方法体

注意事项:

                1.形参列表的数据类型会自动推断

                2.如果形参列表为空,只需要保留()

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

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

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

4.函数式接口         1.什么是函数式接口

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

@Functionallnterface注解检查接口是否符合函数式接口

        2.内置函数式接口的由来
 public static void main(String[] args) {
        fun(arr -> {
             int sum=0;
             for(int n:arr){
                 sum+=n;
             }
            System.out.println("数组的和为:"+sum);
        });
    }

    public static void fun(Operater operater){
         int[] arr={2,3,4,5,6,7,11};
         operater.getSum(arr);
    }

}
@FunctionalInterface
interface Operater{
    //求数组的和
    public abstract void getSum(int[] arr);
}

分析

我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽 象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。

        3.常见的函数式接口--java.util.function

                1.comsumer消费形接口--有参无返回值
  public static void main(String[] args) {
        
        fun((name)->{
            System.out.println("我的姓名"+name);
        },"张三");
    }
    public static void fun(Consumer consumer,String name){
        //Consumer是jdk提供的,不需要我们自己定义函数式接口
        consumer.accept(name);
    }
                2.supplier供给型函数式接口--无参有返回值
  public static void main(String[] args) {
        //new Random().nextInt(10)随机产生随机数0-10之间
        sum(()->new Random().nextInt(10));
    }
    public static void sum(Supplier supplier){
        //supplier.get();的返回类型是泛型
        Integer result = supplier.get();
        System.out.println(result);
    }
                3.Function函数型函数式接口--有参有返回值
 public static void main(String[] args) {
        //函数的长度length()
        //toUpperCase()将小写转为大写
        fun((msg)-> msg.length()
            //msg传进去的字符串
        ,"你好,想吃饭吗?");
    }

    //Function(参数类型的泛型,函数返回结果的泛型)
    public static void fun(Function function, String msg){
        Integer apply = function.apply(msg);
        System.out.println("长度为"+apply);
    }
                4.Predicated断言型接口--当传入一个参数,需要对该参数进行判断时
public static void main(String[] args) {
        //判断名字的长度是否长
        fun(name->name.length()>3?true:false,"迪丽热巴");
    }
    public static void fun(Predicate predicate,String name){
        boolean test = predicate.test(name);
        System.out.println("名字长吗?"+test);
    }
5.方法引用            1.什么是方法引用

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

           2.为什么使用方法的引用
public class Test01 {

    public static void main(String[] args) {
        Consumer c=arr->{
             int sum=0;
             for(int b:arr){
                 sum+=b;
             }
            System.out.println("数组的和为:"+sum);
        };
        fun(c);
    }


    public static void fun(Consumer  consumer){
          Integer[] arr={1,2,3,4,5};
          consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
          int sum=0;
          for (int a:arr){
              sum+=a;
          }
        System.out.println("数组的和为:"+sum);
    }

}

思考:如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了:---方法引用

        3.使用方法引用
public class Test1 {
    public static void main(String[] args) {
        //方法调用
        fun(Test1::sum);
    }
    //有参无返回值
    public static void fun(Consumer consumer){
        Integer[] arr={2,3,4,5,6,7,8,9};
        consumer.accept(arr);

    }
//sum里面的参数类型要和fun里面的参数类型相匹配
    public static void sum(Integer[] arr){
        int sum=0;
        for(int a:arr){
            sum+=a;
        }
        System.out.println("和"+sum);
    }
}
        4.方法引用的常见形式

                   1. 对象::实例方法

                   2.类::静态方法

                   3.类::实例方法

                   4.类::new      

        5.方法引用的分类

                 1.静态方法引用

静态方法引用,Lambda表达式要满足=(参数,..)->类名.静态方法(参数);可以简写为=类名::静态方法

   public static void main(String[] args) {
        //静态方法调用
        List list=new ArrayList<>();
        list.add(3);
        list.add(7);
        list.add(6);
        list.add(9);
        //进行排序
        
        //静态方法
        list.sort(Integer::compare);
        System.out.println(list);
    }
                2.实例方法引用

实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用。

实例方法引用,Lambda表达式要满足=(参数)->实例对象.实例方法(参数)

 public static void main(String[] args) {
        //创建对象
        User user=new User("李四",12);
       //在Lambda表达式中有且只有一条语句,并且这条语句又调用了某个方法
//        Supplier s=()->{
//            return user.getName();
//        };
       // Supplier s=user::getName;
        fun(user::getName);
    }
    public static void fun(Supplier supplier){
        //供给型--无参有返回值
        String s = supplier.get();
        System.out.println(s);
    }
}
class User{
    public String name;
    public int age;

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

    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;
    }
                3.对象方法引用

对象方法引用: 类名::实例方法.    (参数1,参数2)->参数1.实例方法(参数2)

package guan.demo4;

import java.util.function.BiFunction;
import java.util.function.Function;


public class Test3 {
    public static void main(String[] args) {
        
        //对象方法
//        BiFunction b=(str1,str2)->{
//          return str2.equals(str2);
//        };

        //BiFunction双重函数里面有三个参数第一个参数是参数1的泛型,第二个参数是参数2的泛型,第三个参数是返回结果的泛型
        BiFunction  b=String::equals;
        Boolean apply = b.apply("你好", "你好");
        System.out.println(apply);
    }

}
class People{
   public 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;
    }
}
                4.构造方法引用                 构造方法引用: 类名::new         (参数)->new 类名(参数)
/构造方法
       Function function=(name)->{
         return new People(name);
       };
       Function function=People::new;
       People people = function.apply("李四");
       System.out.println(people);
6.stream流

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

        1.什么是stream流

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

注意:stream流只是加工处理数据,不保存数据

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

思考:这段代码中含有三个循环,每一个作用不同:

        1.首先筛选所有姓张的人;

        2.然后筛选名字有三个字的人;

        3.最后进行对结果进行打印输出。

每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。 --使用stream

        3.使用stream流
public class Test {
    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰","何线程");
        //使用stream()流
        //调用stream流
        //filter(需要断言型)--过滤器
        //startsWith以什么开始
       //获取流
        list.stream()
                .filter(item->item.startsWith("张"))
                .forEach(item-> System.out.println(item));
    }
}

对集合的操作语法简洁:性能比传统快。

        4.如何获取stream流对象                 1.通过Collection(集合)对象的stream()或者parallelStream()方法
        //创建一个集合
        List list=new ArrayList();
        list.add("你好");
        list.add("我好");
        list.add("大家好");
        //获取stream流
        Stream stream = list.stream();
        //list.parallelStream串行
                2.通过Arrays(数组)类的stream()方法
 //创建一个数组
        String[] array={"广州好迪","滴答滴答","哗啦哗啦"};
        //获取stream流
        Stream stream1 = Arrays.stream(array);
                3.通过stream接口的of(),iterate(),generate()方法
 Stream stream2 = Stream.of(2, 3, 4, 5, 6, 9);
                4.通过intstream,longstream,doublestream接口中的of,range,rangeclosed方法
         //打印的话是1-19--rang不包括右边
        LongStream range = LongStream.range(1, 20);
        //打印1-20--rangClosed包括右边
        LongStream.rangeClosed(1,20).forEach(System.out::println);
        5.stream流中常见的api

中间操作api: 一个操作的中间链,对数据源的数据进行操作。而这种操作的返回类型还是一个Stream对象。

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

注意:无论执行多少中间操作,只要没有执行终止操作,中间操作就不会执行

                1.中间操作filter--过滤器
        //filter(需要断言型)--过滤器
        //startsWith以什么开始
       //获取流
        list.stream()
                .filter(item->item.startsWith("张"))
                .forEach(item-> System.out.println(item));
    }
                2.map

map--接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

//根据map--名字最长的 --map里面是一个函数型接口--有参有返回值
   personList.stream()
                  .sorted((o1,o2)->o1.getAge()-o2.getAge())
                  .forEach(System.out::println);
//即需要name有需要age
 personList.stream()
                .map(item->{
                     Map m=new HashMap<>();
                     m.put("name",item.getName());
                     m.put("age",item.getAge());
                    return m;
                })
                  .forEach(System.out::println);
                3.sorted
  //根据年龄排序--sorted
       personList.stream().sorted(((o1, o2) -> o1.getAge()- o2.getAge())).forEach(System.out::println);
               4.终端操作collect--收集成为一个新的集合或者其他
        //收集 -女生并且国籍是中国的
        List collect = personList.stream()
                .filter(item -> item.getCountry().equals("中国"))
                .filter(item -> item.getSex() == 'F')
                .collect(Collectors.toList());
        System.out.println(collect);
               5.foreach

.forEach(System.out::println);

                5.find,match

                             find查找

 //findFirst  查找满足条件的第一个
        Optional first = personList.stream()
                .filter(item -> item.getCountry() == "中国")
                .findFirst();
        System.out.println(first.get());
        //findAny匹配任意一个,适合并行流
        Optional any = personList.parallelStream()
                .filter(item -> item.getSex() == 'F')
                .findAny();
        System.out.println(any.get());

                        match匹配

        //anyMatch--满足其中一个返回true--要求括号里面的是一个断言型的
        //allMath--所有的元素都满足返回true
        //nonelMath--没有一个人符合返回true
        boolean b = transactions.stream()
                .map(ietm -> ietm.getTrader())
                .anyMatch(item -> item.getCity() == "Milan");
        System.out.println(b);

                6.reduce规约

规约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和,求乘积和求最值操作

   //求年龄的和--参数和返回类型必须一致
        Optional reduce = personList.stream()
                .map(item -> item.getAge())
                .reduce((o1, o2) -> o1 + o2);
        System.out.println(reduce.get());
        //reduce: 18,24->18+24->42 ,42,22->44+22-66

  Integer reduce = personList.stream()
                .map(item -> item.getAge())
                .reduce(10, (a, b) -> a + b);
        System.out.println(reduce);
//10+(a+b)的值
                7.聚合 min max count

                        count--可以统计人数

long l = personList.stream()
                .filter(item -> item.getCountry().equals("中国"))
                .count();
        System.out.println(l);

                        max--最大值

Optional max = transactions.stream()
                .max((o1, o2) -> o1.getValue() - o2.getValue());
        System.out.println(max.get());

                        min--最小值

 Optional min = transactions.stream()
                .min((o1, o2) -> o1.getValue() - o2.getValue());
        System.out.println(min.get());
7.新增的时间日期类         1.旧的时间日期的缺点                 1.设计比较乱: Date日期在java.util和java.sql也有,而且它的时间格式转换类在java.text包。                 2.线程不安全。         2.新增的时间日期类有哪些                 1.LocalDate: 表示日期类。格式默认:yyyy-MM-dd
  //获取当前的时间
        LocalDate now = LocalDate.now();
       // System.out.println(now);
        //指定日期
        LocalDate of = LocalDate.of(2000, 07, 12);
       // System.out.println(of);
                2.LocalTime: 表示时间类。格式默认: HH:mm:ss
//获取当前时间
        LocalTime now1 = LocalTime.now();
        System.out.println(now1);
        //指定时间
        LocalTime of1 = LocalTime.of(9, 33, 54);
        System.out.println(of1);
                3.LocalDateTime: 表示日期时间类 格式默认: yyyy-MM-dd t HH:mm:ss sss
 //获取当前日期时间
        LocalDateTime now2 = LocalDateTime.now();
        System.out.println(now2);
        //指定日期时间
        LocalDateTime of2 = LocalDateTime.of(of, of1);
        System.out.println(of2);
        LocalDateTime of3 = LocalDateTime.of(2021, 9, 20, 10, 04, 33);
        System.out.println(of3);
                4.DatetimeFormatter:日期时间格式转换类。
 //需要转为什么样的格式
        DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd");
        //将字符串按照dateTimeFormatter的格式转换
        LocalDate parse = LocalDate.parse("1999-11-12", dateTimeFormatter);
        System.out.println(parse);
        //将日期转变为字符串
        String format = parse.format(dateTimeFormatter);
        System.out.println(format);
                5.Instant: 时间戳类。
  //获取到当前的时间戳 
        Instant now3 = Instant.now();
        System.out.println(now3);
        //获取时间戳的数值  时间戳数值是从1970-01-01 00:00:00开始到当前时间所经过的秒数
        long epochSecond = now3.getEpochSecond();
        System.out.println(epochSecond);
                6.Duration: 用于计算两个日期时间类
          Duration between = Duration.between(of3,now2);
        //相差的天数
        System.out.println(between.toDays());

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020147.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号