1. 程式人生 > 實用技巧 >## JDK8新特性

## JDK8新特性

JDK8新特性

目錄

一、Lambda表示式:

Lambda表示式:

​ 1、特殊的匿名內部類,語法更簡介;

​ 2、Lambda表示式允許把函式作為一個方法的引數(函式作為方法引數傳遞),將程式碼像資料一樣傳遞;

Lambda引入了新的操作符:->(箭頭操作符),->將表示式分成兩部分

​ 1、左側:(引數1,引數2·····)表示引數列表

​ 2、右側:{}內部是方法體

~注意事項:

​ ~形參列表的資料型別會自動推斷

​ ~如果形參列表為空,只需保留()

​ ~如果形參只有一個,()可以省略,只需要引數的名稱即可

​ ~如果執行語句只有一句,且無返回值,{}可以省略,若有返回值,則若想省去{},則必須同時省略return,且執行語句也保證只有一句

Typora

二、函式式介面:

  • 如果一個介面只有一個抽象方法,則該介面稱為函式式介面,函式式介面可以使用Lambda表示式,Lambda表示式會被匹配到這個抽象方法上。

  • @Functionallnterface註解檢測介面是否符合函式式介面

    /**
     * Lambda表示式的使用
     */
    public class Demo1 {
        public static void main(String[] args) {
            //匿名內部類
            Usb usb = new Usb() {
                @Override
                public void service() {
                    System.out.println("滑鼠開始工作了~~~~~~~~~~");
                }
            };
    
            //Lambda表示式
            run(() -> System.out.println("滑鼠開始工作了~~~~~~~~~~"););
        }
    
        public static void run(Usb usb) {
            usb.service();
        }
    }
    
    /**
     * 函式時介面
     */
    @FunctionalInterface
    interface Usb {
        void service();
    }
    

三、函式式介面使用:

Consumer消費型介面

Supplier供給型介面

Function函式型介面

predicate斷言型介面

/**
 * Lambda表示式的使用
 */
public class Demo1 {
    public static void main(String[] args) {
        //匿名內部類
        Consumer<Double> consumer = new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println("今晚李公子消費" + o);
            }
        };
        happy(consumer, 1000.0);

        //Lambda表示式(消費型介面)
        happy(d -> System.out.println("今晚李公子消費" + d), 2000.0);

        //Lambda表示式(供給型介面)
        System.out.println(Arrays.toString(getNums(() -> new Random().nextInt(100), 5)));

        //Lambda表示式(函式型介面)
        System.out.println(handerString(a -> a.trim().toUpperCase(), "  abc  "));

        //Lambda表示式(斷言型介面)
        List<String> list = new ArrayList(){{
            add("張三");
            add("李四");
            add("王五");
            add("張九");
        }};
        System.out.println(filterName(str -> str.startsWith("張"), list));

    }

    //Consumer消費型介面
    public static void happy(Consumer<Double> consumer, Double money) {
        consumer.accept(money);
    }

    //Supplier供給型介面
    public static int[] getNums(Supplier<Integer> supplier, int count) {
        int[] arr = new int[count];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = supplier.get();
        }
        return arr;
    }

    //Function函式型介面
    public static String handerString(Function<String, String> function, String str) {
        return function.apply(str);
    }

    //predicate斷言型介面
    public static List<String> filterName(Predicate<String> predicate, List<String> list){
        List<String> resultList = new ArrayList<>();
        for(String str : list){
            if(predicate.test(str)){
                resultList.add(str);
            }
        }
        return resultList;
    }


}

四、方法引用

​ 方法引用是lambda表示式的一種簡寫形式。如果lambda表示式方法體中只有是呼叫一個特定的已經存在的方法,則可以使用方法引用

​ 常見形式:

​ 物件::例項方法

​ 類::靜態方法

​ 類::例項方法

​ 類::new

五、方法引用使用

/**
 * Lambda表示式的使用
 */
public class Demo1 {
    public static void main(String[] args) {
        Consumer<String> consumer = s -> System.out.println(s);
        //1、物件::例項方法
        Consumer<String> consumer1 = System.out::print;
        consumer1.accept("你好");

        /////////////////////////////////////////////////////////////////////////

        Comparator<Integer> comparator =(o1, o2) -> Integer.compare(o1, o2);
        //2、類::靜態方法
        Comparator<Integer> comparator1 = Integer::compare;
        System.out.println(comparator1.compare(2, 1));

        /////////////////////////////////////////////////////////////////////////

        Function<Employee, String> function = e -> e.getName();
        //3、類::例項方法
        Function<Employee, String> function1 = Employee::getName;
        System.out.println(function.apply(new Employee("張三", 10.0)));

        /////////////////////////////////////////////////////////////////////////

        //4、類::new
        Supplier<Employee> supplier = () -> new Employee("李四",18);
        Supplier<Employee> supplier1 = Employee::new;
        System.out.println(supplier1);
    }
}

class Employee{
    private String name;
    private double money;

    public Employee(String name, double money) {
        this.name = name;
        this.money = money;
    }

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

    public Employee() {

    }

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

    public void setMoney(double money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public double getMoney() {
        return money;
    }
}

六、Steram API

1、什麼是Steram

流(Stream)中儲存對集合或陣列資料的操作。和集合類似,但集合中儲存的是資料。

2、Stream特點

Stream自己不會儲存元素

Stream不會改變源物件。相反,他們會返回一個持有結果的新Stream

Stream操作時延時的。這意味著他們會等到需要結果的時候才執行

3、Stream使用步驟

建立

​ 新建一個流

中間操作

​ 在一個或多個步驟中,將初始化Stream轉化到另一個Stream的中間操作

終止操作

​ 使用一個終止操作來產生一個結果。該操作會強制它之前的延遲操作立即執行。在這之後,該Stream就不能使用

4、建立Stream

通過Collection物件的stream()或parallelStream()方法

通過Arrays類的stream()方法

通過Stream介面的of(),iterate(),generate()方法

通過IntStream、LongStream、DoubleStream介面中的of、range、rangeClosed方法

/**
 * Lambda表示式的使用
 */
public class Demo1 {
    public static void main(String[] args) {
        //1、通過Collection物件的stream()或parallelStream()方法
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("huawei");
        list.add("xiaomi");
//        Stream<String> stream = list.stream();    //序列流
        Stream<String> stringStream = list.parallelStream();    //並行流
        //遍歷
//        stream.forEach(s -> System.out.println(s));
        stringStream.forEach(System.out::println);

//////////////////////////////////////////////////////////////////////////

        //2、通過Arrays類的stream()方法
        String[] arr = {"aaa","bbb","ccc","ddd"};
        Stream<String> s = Arrays.stream(arr);
        s.forEach(System.out::println);

//////////////////////////////////////////////////////////////////////////

        //3、通過Stream介面的of(),iterate(),generate()方法
        Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50, 60);
        stream.forEach(System.out::println);

        //迭代流
        System.out.print("--------------生成流---------------");
        Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
        iterate.limit(10).forEach(System.out::println);

        //生成流
        System.out.print("--------------生成流---------------");
        Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
        generate.limit(10).forEach(System.out::println);


//////////////////////////////////////////////////////////////////////////

        //4、通過IntStream、LongStream、DoubleStream介面中的of、range、rangeClosed方法
        System.out.print("--------------IntStream通過of---------------");
        IntStream intStream = IntStream.of(100, 200, 300, 400);
        intStream.forEach(System.out::println);

        System.out.print("--------------IntStream通過range---------------");
        IntStream range = IntStream.range(0, 10);
        range.forEach((System.out::println));

        System.out.print("--------------IntStream通過rangeClosed---------------");
        IntStream rangeClosed = IntStream.rangeClosed(0, 10);
        rangeClosed.forEach((System.out::println));
    }
}

5、中間操作、終止操作

中間操作

filter、limit、skip、distinct、sorted

map

parallel

public class Demo1 {
    public static void main(String[] args) {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("小王", 100));
        list.add(new Employee("小張", 200));
        list.add(new Employee("小李", 300));
        list.add(new Employee("小孫", 400));
        list.add(new Employee("小劉", 500));
        list.add(new Employee("小王", 100));

        //中間操作1
        //1、filter 過濾
        System.out.println("--------------filter 過濾-------------");
        list.stream().filter(e -> e.getMoney() > 200).forEach(System.out::println);

        //2、limit 限制
        System.out.println("--------------limit 限制-------------");
        list.stream().limit(2).forEach(System.out::println);

        //3、skip 跳過
        System.out.println("--------------skip 跳過-------------");
        list.stream().skip(1).forEach(System.out::println);

        //4、distinct 去重
        System.out.println("--------------distinct 去重-------------");
        list.stream().distinct().forEach(System.out::println);

        //5、sorted 排序
        System.out.println("--------------sorted 排序-------------");
        list.stream().sorted((e1, e2) -> Integer.compare(e1.getMoney(), e2.getMoney())).forEach(System.out::println);

        ////////////////////////////////////////////////////////////////////////////////

        //中間操作2
        list.stream().map(e -> e.getName()).forEach(System.out::println);

        ///////////////////////////////////////////////////////////////////////////////

        //中間操作3 採用paraller多執行緒效率高
        List<String> integers = new ArrayList<>();
        for (int i = 0; i < 5000000; i++) {
            integers.add(UUID.randomUUID().toString());
        }
        //序列
        long start = System.currentTimeMillis();
        long count = integers.stream().sorted().count(); //序列
//      long count = integers.parallelStream().sorted().count();//並行
        System.out.print(count);
        long end = System.currentTimeMillis();
        System.out.println("序列用時:"+(end-start));

    }
}

class Employee {
    private String name;
    private Integer money;

    public Employee(String name, Integer money) {
        this.name = name;
        this.money = money;
    }

    public Employee() {
    }

    public String getName() {
        return name;
    }

    public Integer getMoney() {
        return money;
    }

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

    public void setMoney(Integer money) {
        this.money = money;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return name.equals(employee.name) &&
                money.equals(employee.money);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, money);
    }
}
終止操作

forEach、min、max、count

reduce、collect

public class Demo1 {
    public static void main(String[] args) {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("小王", 100));
        list.add(new Employee("小張", 200));
        list.add(new Employee("小李", 300));
        list.add(new Employee("小孫", 400));
        list.add(new Employee("小劉", 500));
        list.add(new Employee("小王", 100));

        //終止操作foreach
        list.stream().filter(e -> {
            System.out.println("過濾了");
           return e.getMoney()>100;
        });
//                .forEach(System.out::println);

        ////////////////////////////////////////////////

        //終止操作reduce
        Optional<Integer> reduce = list.stream().map(e -> e.getMoney()).reduce((x, y) -> x + y);
        System.out.print(reduce);

        //終止操作collect,將所有員工姓名封裝成一個list
       list.stream().map(e -> e.getName()).collect(Collectors.toList()).forEach(System.out::println);
    }
}

class Employee {
    private String name;
    private Integer money;

    public Employee(String name, Integer money) {
        this.name = name;
        this.money = money;
    }

    public Employee() {
    }

    public String getName() {
        return name;
    }

    public Integer getMoney() {
        return money;
    }

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

    public void setMoney(Integer money) {
        this.money = money;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return name.equals(employee.name) &&
                money.equals(employee.money);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, money);
    }
}

七、新時間API

1、以往時間API存在問題:

執行緒安全問題、設計混亂
public class Demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //SimpleDateFormat執行緒不安全
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //建立執行緒池
        ExecutorService pool = Executors.newFixedThreadPool(10);
        //SimpleDateFormat執行緒不安全需要同步程式碼塊
        Callable<Date> objectCallable = () -> {
            synchronized (sdf) {
                return sdf.parse("2020-04-25");
            }
        };
        List<Future<Date>> list = new ArrayList<>();
        //開啟十個執行緒
        for (int i = 0; i < 10; i++) {
            Future<Date> submit = pool.submit(objectCallable);
            list.add(submit);
        }
        //列印結果
        for (Future<Date> future : list) {
            System.out.println(future.get());
        }
        pool.shutdown();

        /////////////////////////////////////////////////////////////////////
        
        //新時間API:DateTimeFormatter、LocalDate執行緒安全
        pool = Executors.newFixedThreadPool(10);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        //SimpleDateFormat執行緒不需要需要同步程式碼塊
        Callable<LocalDate> localDateCallable = () -> LocalDate.parse("2020-04-25",dtf);
        List<Future<LocalDate>> list1 = new ArrayList<>();
        //開啟十個執行緒
        for (int i = 0; i < 10; i++) {
            Future<LocalDate> submit = pool.submit(localDateCallable);
            list1.add(submit);
        }
        //列印結果
        for (Future future : list) {
            System.out.println(future.get());
        }
        pool.shutdown();
    }
    }

2、本地化日期時間APl

LocalDate
LocalTime
LocalDateTime
public class Demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1、建立本地時間
        LocalDateTime localDateTime = LocalDateTime.now();

        //2、自定義時間
        LocalDateTime of = LocalDateTime.of(2020, 10, 12, 9, 10);
        System.out.println(localDateTime.getYear());
        System.out.println(localDateTime.getMonthValue());
        System.out.println(localDateTime.getDayOfMonth());
        System.out.println(localDateTime.getDayOfMonth());

        //3、新增兩天
        LocalDateTime localDateTime1 = localDateTime.plusDays(2);
        System.out.println(localDateTime1);

        //4、減少一個月
        LocalDateTime localDateTime2 = localDateTime.minusMonths(1);
        System.out.println(localDateTime2);
        
    }

}

3、Instant:時間戳

//1、建立Instant,時間戳
Instant instant = Instant.now();
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
System.out.println(System.currentTimeMillis() );

//2、新增減少時間
Instant instant1 = instant.plusSeconds(10);
System.out.println(Duration.between(instant, instant1).toMillis());

4、ZoneId:時區

//3、ZoneId
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for(String string : availableZoneIds){
    System.out.println(string);
}
System.out.println(ZoneId.systemDefault().toString());

5、Date、Instant、LocalDateTime的轉換

//1、Date -> Instant -> LocalDateTime
Date date = new Date();
Instant instant2 = date.toInstant();
System.out.println(instant2);

LocalDateTime localDateTime = LocalDateTime.ofInstant(instant2, ZoneId.systemDefault());
System.out.println(localDateTime);

//2、LocalDateTime -> Instant -> Date
Instant instant3 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
System.out.println(instant3);
Date from = Date.from(instant3);
System.out.println(from);

6、DateTimeFormatter:格式化類

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//把時間轉換成字串
String format = dtf.format(LocalDateTime.now());
System.out.println(format);

//把字串轉換成時間
LocalDateTime parse = LocalDateTime.parse("2020-10-12 10:10:10", dtf);
System.out.println(parse);

八、總結

1、Lambda表示式:

​ 允許把函式作為一個方法引數傳遞

2、函式式介面使用:

​ Consumer消費型介面

​ Supplier供給型介面

​ Function函式型介面

​ predicate斷言型介面

3、Stream API

​ 把對資料的操作封裝成一個流

​ 步驟:建立、中間操作、終止操作

4、新時間API