java8新特性

来源:互联网 发布:sql范围查询语句 编辑:程序博客网 时间:2024/06/07 10:56
Lambda表达式 
一  基础语法: java8 引入一个新的操作符 “->” 该操作符称为操作符或lambda 操作符
                         操作符将Lambda 表达式拆分成两个部分
                         左侧:Lambda 表达式的参数列表
                         右侧:Lambda 表达式所执行的功能,即Lambda体
     语法格式一、无参,无返回值
                            () -> System.out.println("hello java8");

     语法格式二、有一个参数,并且无返回值 (若参数只有一个 小括号可以不写)
                            (x)-> System.out.println(x);
                           例 有个Student 接口 里面只有一个方法 void student(T t);
                           Student<String> s = (x)-> System.out.println(x);
                            s.student(“hello”);
                            即打印出hello
 
        语法格式三:有两个以上的参数,有返回值,并且Lambda体中有多条语句
                           注意:该接口必须是函数式接口 即接口内部只有一个方法
 
        语法格式四:有两个以上的参数,有返回值,并且Lambda体中有一条语句    return 和大括号可以不写

         语法格式五:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM可以根据上下文推断出数据类型,即“类型推断”


二、四大内置核心函数式接口 
         1、Consumer<T> : 消费型接口 (无返回值)
                           void accept(T t);
         2、Supplier<T>     :  供给型接口 (有返回值)
                            T get();
         3、Function(T,R)  :   函数型接口 (有参,有返回值)
                            R apply(T t);
         4、Predicate<T>  :   断言型接口 (做判断操作)
                            boolean test(T t);

注意:函数式接口 是一个接口 里面有且仅有一个方法,如在接口上部添加 @FunctionalInterface  注解,若如此 此接口在写一个未实现的方法是不会通过编译
  1、Consumer<T> : 消费型接口 (无返回值)
                           void accept(T t);


    2、Supplier<T>     :  供给型接口 (有返回值)
                            T get();
 

     3、Function<T,R>  : 函数型接口
                            R apply(t)

     4、Boolean  Predicate<T> : 断言型函数接口
                          boolea test(t);
 
三、方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”
                         (可以理解为方法引用是Lambda 表达式的另外一种表现形式)
                主要有三种语法格式:
                    对象::实例方法
                    类::静态方法
                    类::实例方法
      注意:1、Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型保持一致;
                 2、若Lambda 参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用 ClassName :: method 
        注: 这方面知识点想要熟练使用要十分熟悉java类库或项目中的方法,方法引用需要返回值和参数全部对应上。本人水平,阅历经验需要加强,无法信手拈来java内部的方法,现实项目中可以用自己编写的方法。
    // 对象::实例方法
    @Test
    public void test5() {
        Person person = new Person(10, "张三");
        Consumer<String> consumer = person::setName;
        consumer.accept("abcedf");
        System.out.println(person.getName());
    }
    此处程序结果为 abcdedf 。    (留个映像,每次编程往这上面靠,时间长了也就掌握了)
    // 类::静态方法
    @Test
    public void test6() {
        Comparator<Integer> comparable = Integer::compare;
        int num = comparable.compare(100, 20);
        System.out.println(num);
    }
     此处程序结果为1  
    // 类::实例方法
    @Test
    public void test7() {
        Function<String, Integer> function = Integer::parseInt;
        String str = "120";
        int num = function.apply(str);
        System.out.println(num);
    }
      此处程序结果为120  

    // 构造器引用
    @Test
    public void test8() {
        Supplier<Person> supplier = Person::new;
        Person person = supplier.get();
        System.out.println(person.toString());
    }

// 数组引用
    @Test
    public void test9() {
        Function<Integer, String[]> function = x -> new String[x];
        int num = function.apply(5).length;
        Consumer<Integer> consumer = System.out::println;
        consumer.accept(num);
        
        function = String[]::new;
        num = function.apply(6).length;
        consumer.accept(num);
    }
   程序运行结果为 5  6;



四、  Stream 流
           官方解释看了那么多,说白了 流 就是另外一种对数组或集合中的数据的操作方式。原理是 :将数据源即数组或集合转化成流,之后像过滤纯净水一样对此流进行一系列特定的操作,得到目标数组或集合,同时原来的数组或集合不被破坏。举个例子:假如 以前要拿出一个list集合中的特定数据,要用for循环(无论增强还是普通的for循环),然后在for循环里拿到一个数据进行操作。现在用流不在用for循环,操作是先将list转化成流,在此基础上进行filer过滤操作等等,这个时候每个数据都会执行filer等操作,然后在返回成目标listlist。看似流比for复杂,但其实用流只需要一行代码搞定,而用for循环则至少三行。
        一、操作步骤
            1、创建Stream
            2、中间操作
            3、终止操作

            1、创建Stream
@Test
    public void test1() {
        // 1、通过#Collection 系列集合提供的stream()或parellerStream()
        List<String> strs = new ArrayList<>(); // 集合
        Stream<String> stream = strs.stream();// 转化成流
       
        // 2、通过#Arrays()中的静态方法stream()获取数组流
        String[] args = new String[5];// 数组
        stream = Arrays.stream(args);
       
             // 3、通过#Stream()类中的静态方法of()
        stream = Stream.of("a""b""c");
      
             // 4、创建无限流 (暂无发现使用场合)
        // 迭代
        Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2);
        // 生成
        Stream<Integer> stream3 = Stream.generate(() -> (int) (Math.random() * 10));
    }
        2、中间操作
          1) 筛选与切片
                filer - 接Lambda表达式,从流中过滤某些元素;
                limit - 截断流,使其元素不超过给定的数量
                skip - 跳过元素,返回一个扔掉N元素之后的流,若元素不足N个,则返回一个空流,与limit互补
                distinct - 筛选,通过流所生成元素的hashCode() 和equals()去除重复元素。
        注意:在没执行终止操作时,中间操作不会被执行,这种机制称之为"惰性求值"

@Test
    public void test2() {
        List<Personrequest = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"));
        request.stream().filter(t -> {
            System.out.println("filter....");
            return t.getAge() > 15;
        }).forEach(System.out::println);
    }
运行结果
filter....
Person [name=张三, age=20]
filter....
filter....

limit
    @Test
    public void test2() {
        List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(16, "end"), new Person(10, "李四"),
                new Person(15, "王五"));
        request.stream().filter(t -> {
            System.out.println("filter正在被执行");
            return t.getAge() > 15;
        }).limit(2).forEach(System.out::println);
    }
    这里需要注意的是 limit 只会输出满足条件的数据,但程序执行次数却不一定,程序会一直执行直到满足条件的数据到2个;
    如 上面程序运行的结果为
filter正在被执行
Person [name=张三, age=20]
filter正在被执行
Person [name=end, age=16]
    切换list的元素的位置;
    @Test
    public void test2() {
        List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
                new Person(16, "end"));
        request.stream().filter(t -> {
            System.out.println("filter正在被执行");
            return t.getAge() > 15;
        }).limit(2).forEach(System.out::println);
    }
   上面的程序运行结果为:
filter正在被执行
Person [name=张三, age=20]
filter正在被执行
filter正在被执行
filter正在被执行
Person [name=end, age=16]
这种现象在某种意义上提高了代码运行效率
skip 跳过
    @Test
    public void test2() {
        List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
                new Person(16, "end"));
        request.stream().filter(t -> {
            System.out.println("filter正在被执行");
            return t.getAge() > 15;
        }).skip(1).forEach(System.out::println);
    }
注意:因为这里的skip写在filter的后面,所以这里跳过的是满足filter的数据,因此打印结果为
filter正在被执行
filter正在被执行
filter正在被执行
filter正在被执行
Person [name=end, age=16]
    同理:skip也可以写在filter的前面,那么就是先跳过后过滤。

distinct - 筛选,通过流所生成元素的hashCode() 和equals()去除重复元素。
注意:要实现此方法,需要在person类或者特定pojo类中重写hashCode()和equals()方法
    @Test
    public void test2() {
        List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
                new Person(16, "end"), new Person(16, "end"));
        request.stream().filter(t -> {
            System.out.println("filter正在被执行");
            return t.getAge() > 15;
        }).distinct().forEach(System.out::println);
    }
运行结果为:
filter正在被执行
Person [name=张三, age=20]
filter正在被执行
filter正在被执行
filter正在被执行
Person [name=end, age=16]
filter正在被执行
        2)映射
           map - 接收Lambda表达式,将元素转成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
           flatMap - 接收一个函数作为参数,将流中的每个值换成另一个流,然后把所有流链接成一个新的流
    public void test3() {
        List<Stringrequest = Arrays.asList("a""b""c""d""e");
        List<String> respose = request.stream().map(t -> t.toUpperCase()).collect(Collectors.toList());
        respose.forEach(System.out::print);
    }
运行结果为:ABCDE
 

   3、终止操作
    1) 归约
        reduce(T identity , BinaryOperator) / reduce(BinaryOperator) --可以将流中的元素反复结合起来,得到一个新的值。
   @Test
    public void test4() {
        String str = "1abc1dec104"// 一个字符串
        char[] c = str.toCharArray();// 转化成数组
        List<String> strings = new ArrayList<String>();
        for (char d : c) {
            strings.add(String.valueOf(d));// 将char类型的数组转成String类型的list
        }
        String newStr = strings.stream() // 转化成流
                .filter(t -> t.matches("[a-zA-Z]+")) // 过滤出字母
                .reduce("", (xy) -> x + y); // 将结果集归约成一个字符串
        System.out.println(newStr);
    }
   运行结果为:abcdec  
    2)收集
    collect -- 将流转化成其他形式,接收一个Collector 接口的实现,用于给Stream中元素做汇总的方法
  
    @Test
    public void test5() {
        List<String> strList = Arrays.asList("aa""bb""cc""dd""ee""ee");
        strList.forEach(System.out::print);
        System.out.println("---------------------------");
        Set<String> strSet = strList.stream().map(t -> t.toUpperCase()).collect(Collectors.toSet());
        strSet.forEach(System.out::print);
    }

0 0
原创粉丝点击