JDK8 新特性学习笔记

java8新特性学习

java8的特点

  1. 速度更快(修改了HasMap、HasSet、CurrentHasMap等存储结构)
  2. 代码更少(增加了新的语法Lambda表达式)
  3. 强大的Stream API
  4. 便于并行
  5. 最大化减少空指针异常

1.Lambda表达式

1.1、Lambda表达式是什么?

Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

1.2、Lambda表达式的基础语法

Java8中引入了一个新的操作符“->”,该操作符称为箭头操作符或者Lambda操作符,该操作符将Lambda表达式拆分成两个部分:

左侧:Lambda表达式的参数列表。

右侧:Lambda表达式中需要执行的功能,即Lambda体。

语法格式一:无参数,无返回值

() -> System.out.println("hello Lambda");

语法格式二:有一个参数,并且无返回值

(x) -> System.out.println(x);

语法格式三:若只有一个参数,小括号可以省略不写

x -> System.out.println(x);

语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句

Comparator<Integer> com = (x,y) -> {
    System.out.println("函数式接口");
    return Integer.compare(x,y);
};

语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略不写

Comparator<Integer> com = (x,y) -> Integer.compare(x,y);

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型

(Integer x,Integer y) -> Integer.compare(x,y);

源代码

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.Consumer;

import org.junit.jupiter.api.Test;

public class TestLambda2 {

    /*
     * Lambda基本语法:参数列表 -> 方法体
     */
    
    /*
     * 语法格式一:无参数,无返回值
     *  () -> System.out.println("Hello World");
     */
    @Test
    public void test1() {
        int num = 0; //jdk8中当匿名内部类中使用的变量,会自动隐式添加final关键字,匿名内部类中依然不能将变量进行加减操作。
        Runnable r = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("hello world"+num);
            }
        };
        r.run();

        System.out.println("=============================");
        
        Runnable r1 = () -> System.out.println("hello lambda"+num);
        r1.run();
    }
    
    /*
     * 语法格式二:有一个参数,没有返回值
     */
    @Test
    public void test2() {
        Consumer<String> c = (x) -> System.out.println(x);
        c.accept(1+"");
        
        //Lambda表达式中如果参数只有一个,那么括号可以省略不写
        Consumer<Object> c1 = x -> System.out.println("哈哈哈");
        c1.accept("ABC");
    }
    
    /*
     * 语法格式三:有两个参数,有返回值,Lambda体中有多条语句
     */
    @Test
    public void test3() {
        Comparator<Integer> com = (x,y) -> {
            System.out.println("好好学习,天天向上!");
            return x+y;
        };
        
        int result = com.compare(20, 30);
        System.out.println("result:"+result);
        
        //如果Lambda体中只有一条语句,可以省略“{}”和return
        Comparator<Integer> c = (Integer x,Integer y) -> Integer.compare(x, y);
        int num = c.compare(30, 30);
        System.out.println("maxNub"+num);
        
        //由于JVM的类型推断,所以Lambda参数列表的数据类型,可以省略不写
        Comparator<Integer> c1 = (x,y) -> Integer.compare(x, y);
        int num1 = c1.compare(30, 31);
        System.out.println("maxNub"+num1);
    }
    
    /*
     * 调用自定的函数式接口
     */
    @Test
    public void test4() {
        MyFun myFun = x -> x+100;
        int value = myFun.getValue(100);
        System.out.println("value:"+value);
    }
    
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFun {

    int getValue(int x);
}

练习代码

package com.zgy.deom1;


import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;

public class TestLambda {

    
    List<Employee> emps = Arrays.asList(
            new Employee(101,"张三",18,9999.99),
            new Employee(102,"李四",59,6666.66),
            new Employee(103,"王五",28,3333.33),
            new Employee(104,"赵六",8,7777.77),
            new Employee(105,"田七",38,5555.55)
            );
    
    /*
     * 使用Collections对员工列表进行排序,按工资从多到少比
     * 关于Collections.sort()自定义排序规则,两个参数x和y,如果要按照升序,就是x在前面;相反如果要按照降序,就是y在前面。
     */
    @Test
    public void test1() {
        
        Collections.sort(emps, (x,y) -> Double.compare(y.getSalary(), x.getSalary()));
        for (Employee employee : emps) {
            System.out.println(employee);
        }
    }
    
    /*
     * 定义一个函数式接口,传如一个参数,返回该参数的大写形式
     */
    @Test
    public void test2() {
        
        String str = strHandler("zgy", x -> x.toUpperCase());
        System.out.println("str:"+str);
    }
    
    //小写转大写的方法
    public String strHandler(String str,MyFunction mf) {
        return mf.getValue(str);
    }
    
    /*
     * 声明一个带两个泛型的函数式接口,泛型类型为<T,R> T为参数,R为返回值,接口中声明对应的抽象方法
     * 再使用接口作为参数,计算两个long型参数的和
     * 再计算两个long型参数的积
     */
    @Test
    public void test3() {
        
        //计算和
        System.out.println(getValue(100L, 200L, (x,y) -> x+y));
        
        //计算积
        System.out.println(getValue(500L, 900L, (x,y) -> x*y));
    }
    
    public long getValue(Long x,Long y,MyFunction2<Long, Long> mf) {
        
        return mf.getValue(x, y);
    }
}
package com.zgy.deom1;

public class Employee {

    private int id;
    private String name;
    private int age;
    private double salary;
    
    public Employee() {}
    
    public Employee(int id, String name, int age, double salary) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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 double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction {

    public String getValue(String x);
}
package com.zgy.deom1;

@FunctionalInterface
public interface MyFunction2<T,R> {

    public R getValue(T t1, T t2);
}

1.3、函数式接口

函数式接口:接口中只有一个抽象方法的接口,称为函数式接口,可以使用注解@FunctionalInterface修饰,该注解的作用是可以检查该接口是否为函数式接口。

1.4、Java8内置四大核心函数式接口

image

Consumer<T>:消费型接口

​ void accept(T t);

Supplier<T>:供给型接口

​ T get();

Function<T, R>:函数型接口

​ R apply(T t);

Predicate<T>:断言型接口

​ boolean test(T t);

其它子接口如下图

image

源代码

package com.zgy.deom1;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

/*
 * JDK8 内置四大核心函数式接口
 */
public class TestLambda3 {

    /*
     * 消费式接口:传一个参数,没有返回值
     * Consumer<T>  void accept(T t);
     */
    @Test
    public void test1() {
        say("好好学习,天天向上!", x -> System.out.println(x+new Date()));
    }
    
    public void say(String str, Consumer<String> c) {
        c.accept(str);
    }
    
    /*
     * 供给式接口:没有参数,返回一个结果
     * Supplier<T>  T get();
     */
    @Test
    public void test2() {
        List<Integer> listResult = getNumberArr(() -> {
            List<Integer> list = new ArrayList<>();
            for(int i=0; i<10; i++) {               
                list.add(new Random().nextInt());
            }
            return list;
        });
        
        for (Integer integer : listResult) {
            System.out.println("DATA:"+integer);
        }
    }
    
    public List<Integer> getNumberArr(Supplier<List<Integer>> s){
        return s.get();
    } 
    
    /*
     * 函数式接口:传入一个参数,返回一个结果
     * Function<T,R>  R apply(T t);
     */
    @Test
    public void test3() {
        System.out.println(apply("ZGY:", (x) -> x+new Date()));
    }
    
    public String apply(String a, Function<String, String> f) {
        return f.apply(a);
    };
    
    /*
     * 断言型接口:传入一个参数,返回一个布尔值
     * Predicate<T>  boolean test(T t);
     */
    @Test
    public void test4() {
        System.out.println(test(40, x -> x>0));
    }
    
    public String test(int x, Predicate<Integer> p) {
        if(p.test(x)) {
            return "大于0";
        }else {
            return "小于0";
        }
    }
}

1.5、方法引用与构造器引用

  1. 方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda表达式的另外一种表现形式)

    主要有三种语法格式:

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

    注意:

    1. Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。
    2. 若Lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数,可以用使用ClassName :: method
  2. 构造器引用:

    格式:ClassName :: new

    注意:需要调用的构造器参数列表要与函数式接口中抽象方法的参数列表保持一致

  3. 数组引用:

    格式:Type :: new;

源代码

package com.zgy.deom1;

import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

public class TestMethodRef {

    /*
     * 方法引用和构造器引用
     */
    
    @Test
    public void test1() {
        //对象 :: 实例方法名
        Consumer<String> c = System.out::println;
        c.accept("ZGY");
        
        Employee e = new Employee(111,"ZGY",22,1000);
        Supplier<String> s = e::getName;
        System.out.println(s.get());
    }
    
    @Test
    public void test2() {
        //类名::方法名
        Comparator<Integer> c = Integer::compare;
        System.out.println(c.compare(800, 210));
    }
    
    @Test
    public void test3() {
        //类名::实例方法名
        BiPredicate<String, String> bp = String::equals;
        System.out.println(bp.test("AAA", "AAA"));
    }
    
    @Test
    public void test4() {
        //构造器引用
        Supplier<Employee> e = Employee::new;
        Employee employee = e.get();
        employee.setName("ZGY");
        System.out.println(employee);
    }
}

2、Stream API

2.1、什么是Stream

流(Stream)到底是什么?

流,是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。集合讲的是数据,而流讲的是计算!

注意:

  1. Stream自己不会存储元素。
  2. Stream不会改变源对象,相反他们会返回一个持有结果的新Stream。
  3. Stream是延迟执行的,这意味着它们会等到需要结果的时候才会执行。

2.2、Stream的操作三个步骤

image
  1. 创建Stream源码

    package com.zgy.deom1;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Stream;
    
    import org.junit.jupiter.api.Test;
    
    /*
     * 创建Stream的几种方式
     */
    public class TestStreamAPI1 {
    
     @Test
     public void test1() {
         //1.可以通过Collection系列集合提供的stream()或parallelStream()
         List<String> list = new ArrayList<>();
         Stream<String> stream = list.stream();
         
         //2.通过Arrays中的静态方法stream()获取数组流
         Employee[] employees = new Employee[10];
         Stream<Employee> stream2 = Arrays.stream(employees);
         
         //3.通过Stream类中的静态方法of()
         Stream<String> stream3 = Stream.of("AA","BB","CC","DD");
         
         //4.通过迭代的方式创建无限流
         Stream<Integer> stream4 = Stream.iterate(0, x -> x+2);
         stream4.limit(5).forEach(System.out::println);
         
         //5.通过生成的方式创建无限流
         Stream<Double> stream5 = Stream.generate(() -> Math.random());
         //下面limit、forEach分别是
         stream5.limit(20).forEach(System.out::println);
     }
    }
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容