海阔天空

当前时间为:
欢迎大家来到海阔天空https://www.9713job.com,广告合作以及淘宝商家推广请微信联系15357240395

2020java教程:java8新特性

未分类
2020-09-29 14:39:03
1822677238@qq.com

手机扫码查看

2020java教程:java8新特性

2020java教程:java8新特性

java8新特性

java8概述
java8简称jdk1.8是java语言开发的一个主要版本。
oracle公司于14年3月18日发布java8

支持Lambda表达式
函数式接口
新的Stream API
新的日期 API
其他特性


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

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

import java.util.Comparator;
import java.util.TreeSet;

public class demos{
    public static void main(String[] args) {
        //匿名内部类
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程执行了");
            }
        };
        //Lambda表达式
        Runnable runnable1=()->System.out.println("子线程1执行了");
        new Thread(runnable1).start();
        new Thread(()->System.out.println("子线程3执行了")).start();
        //匿名内部类
        Comparator<String> com=new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        };
        //Lambda表达式
        Comparator<String> com2=(String o1, String o2)-> {
            return o1.length()-o2.length();
        };
        Comparator<String> com3=(o1,o2)->o1.length()-o2.length();
        TreeSet<String> treeSet2=new TreeSet<>(com2);
        TreeSet<String> treeSet3=new TreeSet<>(com3);
    }
}

基本语法:
<函数式接口><变量名>=(参数1,参数2)->{
//方法体
};

Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
左侧:(参数1,参数2…)表示参数列表
右侧:{}内部是方法体

注意事项
形参列表的数据类型会自动判断
如果形参列表为空,只需保留()
如果形参只有一个,()可以省略,只需要参数的名称即可
如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{}
则必须同时省略return,且执行语句也保证只有一句
Lambda不会生成一个单独的内部类文件
=============================
函数式接口

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

@FunctionalInterface 注解检测接口是否符合函数式接口。

@FunctionalInterface
public interface Usb {
    void service();
}

常见函数式接口

常见函数式接口
函数式接口 参数类型 返回类型 说明
Consumer <T>消费型接口 T void void accept(T t);对类型为T 的对象应用操作
Supplier<T>供给型接口 T T get();返回类型为T的对象
Fuction<T,R>函数型接口 T R R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象
Predicate<T>断言型接口 T boolean boolean test(T t);确定类型为T的对象是否满足条件,并返回Boolean类型

//消费型接口

import java.util.function.Consumer;

public class demos{
    public static void main(String[] args) {
        //匿名内部类
        Consumer<Double> con=new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("消费1\t"+aDouble);
            }
        };
        //Lambda表达式
        Consumer<Double> con2=t-> System.out.println("消费2\t"+t);
        happy(con,1000);
        happy(con2,2000);
        happy(t-> System.out.println("消费3\t"+t),3000);
    }
    public static void happy(Consumer<Double> consumer,double money){
        consumer.accept(money);
    }
}
//运行结果
消费1	1000.0
消费2	2000.0
消费3	3000.0

//供给型函数式接口

import java.util.Arrays;
import java.util.Random;
import java.util.function.Supplier;

public class demos{
    public static void main(String[] args) {
        //匿名内部类
        Supplier<Integer> sup=new Supplier<Integer>() {
            @Override
            public Integer get() {
                return new Random().nextInt(100);
            }
        };
        //Lambda表达式
        int[] nums = getNums(() -> new Random().nextInt(100), 5);
        System.out.println(Arrays.toString(nums));
        System.out.println("====");
        int[] nums1 = getNums(sup, 6);
        System.out.println(Arrays.toString(nums1));
    }
    public static int[] getNums(Supplier<Integer> supplier,int count){
        int[] arr=new int[count];
        for(int i=0;i<count;i++){
            arr[i]=supplier.get();
        }
        return arr;
    }
}

//结果
[80, 20, 60, 23, 52]
====
[86, 20, 10, 7, 61, 30]

//函数型接口

import java.util.function.Function;

public class demos{
    public static void main(String[] args) {
        System.out.println(handler(s -> s.toUpperCase(), "hello"));
        System.out.println(handler(s ->{return s.toUpperCase();}, "world"));
        System.out.println(handler(String::toUpperCase, "helloworld"));
    }
    public static String handler(Function<String,String> function,String str){
        return function.apply(str);
    }
}

//结果
HELLO
WORLD
HELLOWORLD

//断言型接口

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class demos{
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("zhangsan");
        list.add("zhangwuji");
        list.add("lisi");
        list.add("lixiaolong");
        list.add("wangwu");
        List<String> result = find(s -> s.startsWith("zhang"), list);
        System.out.println(result.toString());
        List<String> result2 = find(s -> s.startsWith("li"), list);
        System.out.println(result2.toString());
        List<String> result3 = find(s -> s.contains("i"), list);
        System.out.println(result3.toString());
        List<String> result4 = find(s -> s.contains("a"), list);
        System.out.println(result4.toString());
    }
    public static List<String> find(Predicate<String> predicate,List<String> list){
        List<String> result=new ArrayList<>();
        for (String s : list) {
            if(predicate.test(s)){
                result.add(s);
            }
        }
        return result;
    }
}

//结果
[zhangsan, zhangwuji]
[lisi, lixiaolong]
[zhangwuji, lisi, lixiaolong]
[zhangsan, zhangwuji, lixiaolong, wangwu]
=============================
方法引用

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

常见形式:
对象::实例方法
类::静态方法
类::实例方法
类::new

public static void main(String[] args) {
    //对象::实例方法
    Consumer<String> con=System.out::println;
    con.accept("hello");
    //类::静态方法
    Comparator<Integer> com=Integer::compare;
    //类::实例方法
    Function<Character,String> function=Character::getName;
    System.out.println(function.apply('a'));
    //类::new
    Supplier<Student> sup=Student::new;
    System.out.println(sup.get());
}

=============================
stream API

什么是stream?
流(stream)中保存对集合或数组数据的操作。和集合类似,但集合中保存的是数据。

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

Stream使用步骤
创建:创建一个流
中间操作:在一个或多个步骤中,将初始stream转化到另一个stream的中间操作
终止操作:使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,该stream就不能使用了。

创建stream

1.通过Collection对象的stream()或paralleleStream()

List<String> list=new ArrayList<>();
list.add("huawei");
list.add("apple");
list.add("oppo");
list.add("vivo");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
System.out.println("===");
Stream<String> stream2 = list.parallelStream();
stream2.forEach(System.out::println);

2.通过Arrays类的stream()方法

String[] s={"apple","banner","orange"};
Stream<String> stream = Arrays.stream(s);
stream.forEach(System.out::println);

3.通过Stream接口的of()、iterate()、generate()方法

Stream<Integer> stream = Stream.of(10, 20, 30);
stream.forEach(System.out::println);
System.out.println("==迭代流==");
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(5).forEach(System.out::println);
System.out.println("==生成流==");
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(999));
generate.limit(5).forEach(System.out::println);

4.通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法

IntStream stream=null;
stream=IntStream.of(10,20,30);
stream.forEach(System.out::println);
System.out.println("====");
stream=IntStream.range(0,50);//0~49
stream.forEach(System.out::println);
System.out.println("====");
stream=IntStream.rangeClosed(0,50);//0~50
stream.forEach(System.out::println);

中间操作、终止操作

中间操作
filter过滤、limit限制、skip跳过、distinct去重、sorted排序

public static void main(String[] args) {
    List<Emp> list=new ArrayList<>();
    list.add(new Emp("张三",15000));
    list.add(new Emp("李四",17000));
    list.add(new Emp("赵柳",5000));
    list.add(new Emp("李三",8000));
    list.add(new Emp("李三",8000));
    //filter过滤
    System.out.println("----filter过滤工资小于5000的----");
    list.stream().filter(e->e.getBalance()>5000).forEach(System.out::println);
    //limit限制
    System.out.println("----limit限制,只显示3条数据----");
    list.stream().limit(3).forEach(System.out::println);
    //skip跳过
    System.out.println("----skip跳过,跳过头两条数据----");
    list.stream().skip(2).forEach(System.out::println);
    //distinct去重,需重写hashcode和equals方法
    System.out.println("---distinct去重---");
    list.stream().distinct().forEach(System.out::println);
    //sorted排序
    System.out.println("---sorted排序---");
    list.stream()
            .sorted((e1,e2)->Double.compare(e1.getBalance(),e2.getBalance()))
            .forEach(System.out::println);
}

map映射

list.stream().map(Emp::getName).forEach(System.out::println);

parallel并行流

//parallel调用toString()方法,采用多线程,效率快
list.stream().parallel().forEach(System.out::println);

并行流和串行流的区别

List<String> list=new ArrayList<>();
for(int i=0;i<5000000;i++){
    list.add(UUID.randomUUID().toString());
}
System.out.println("添加完毕");
long s=System.currentTimeMillis();
//串行流,单线程,用时14秒
long count = list.stream().sorted().count();
//并行流,多线程,用时0.2秒
long count2 = list.stream().parallel().count();
System.out.println(count);
long e=System.currentTimeMillis();
System.out.println("用时"+(e-s));

终止操作

forEach遍历、min求最小值、max求最大值、count获取元素个数

//forEach遍历
list.stream().filter(t->t.getSalary()>5000)
        .forEach(System.out::println);
//min
System.out.println("获取工资最低的数据");
Optional<Emp> min = list.stream()
        .min((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
System.out.println(min.get());
//max
System.out.println("获取工资最高的数据");
Optional<Emp> max = list.stream()
        .max((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
System.out.println(max.get());
//count
System.out.println("获取元素个数");
System.out.println("数据有"+list.stream().count()+"条");

reduce规约求和、collect收集

//reduce规约
System.out.println("计算总工资");
Optional<Double> sum = list.stream().map(Emp::getSalary).reduce(Double::sum);
System.out.println("总工资为:"+sum.get());
//collect收集
System.out.println("collect收集");
List<String> name = list.stream().map(Emp::getName).collect(Collectors.toList());
for (String s : name) {
    System.out.println(s);
}

=============================
新时间API

之前时间API存在问题,线程安全问题,设计混乱

解决方案

public static void main(String[] args)throws Exception {
    DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMdd");
    ExecutorService ex = Executors.newFixedThreadPool(10);
    Callable<LocalDate> callable=()->LocalDate.parse("20201007",dtf);
    List<Future<LocalDate>> list=new ArrayList<>();
    for(int i=0;i<10;i++){
        Future<LocalDate> future = ex.submit(callable);
        list.add(future);
    }
    for (Future<LocalDate> f : list) {
        System.out.println(f.get());
    }
    ex.shutdown();
}

本地化时间API

LocalDate、LocalTime、LocalDateTime

public static void main(String[] args) {
    //获取本地时间
    LocalDateTime ldt=LocalDateTime.now();
    System.out.println("获取年份:"+ldt.getYear());
    System.out.println("获取月份:"+ldt.getMonthValue());
    System.out.println("获取日期:"+ldt.getDayOfMonth());
    System.out.println("获取星期:"+ldt.getDayOfWeek());
    
    //修改时间 plus增加 min减少
    System.out.println("穿越到明早工作时间");
    System.out.println(ldt.plusHours(17));
    System.out.println("回到十年前");
    System.out.println(ldt.minusYears(10));
}

Instant时间戳、ZoneId时区

public static void main(String[] args) {
    //Instant时间戳
    Instant instant=Instant.now();
    System.out.println(instant.toString());
    System.out.println(instant.toEpochMilli());
    System.out.println(System.currentTimeMillis());
    //添加减少时间
    Instant instant2=instant.plusSeconds(10);
    System.out.println(Duration.between(instant,instant2).toMillis());
    Instant instant3=instant.minusSeconds(10);
    System.out.println(Duration.between(instant,instant3).toMillis());
    //ZoneId时区
    Set<String> zoneIds = ZoneId.getAvailableZoneIds();
    for (String str : zoneIds) {
        System.out.println(str);
    }
    System.out.println("当前时区:"+ZoneId.systemDefault().toString());
}

Date、Instant、LocalDateTime的转换

DateTimeFormatter:格式化类

public static void main(String[] args) {
    //DateTimeFormatter
    DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    //把时间格式化成字符串
    System.out.println(dtf.format(LocalDateTime.now()));
    //把字符串解析成时间
    LocalDateTime localDateTime=LocalDateTime.parse("2020-10-07 18:00:47",dtf);
    System.out.println(localDateTime);
}

java8总结

Lambda表达式:允许把函数作为一个方法的参数传递。

函数式接口:
Consumer、Supplier、Function、predicte

StreamAPI
把对数据的操作封装成一个流
步骤:创建流、中间操作、终止操作

新时间API

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注