当前位置: 移动技术网 > IT编程>开发语言>Java > 荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)

荐 Java语言基础之JDK1.8新特性(Lambda表达式、函数式接口、Stream流、新的日期API)

2020年07月12日  | 移动技术网IT编程  | 我要评论

Java8概述

是Java语言开发的一个主要版本。Oracle公司于2014年3月18日发布Java8版本。

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

Lambda表达式

特殊的内部类,语法更加简洁。

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

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

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

  • 左侧:(参数1, 参数2…)
  • 右侧:{} 内部是方法体

注意事项

  1. 形参列表的数据类型会自动判断
  2. 如果形参列表为空,只需保留()
  3. 如果形参只有1个,()可以省略,只需要参数的名称即可
  4. 如果方法体中只有一句代码,或者无返回值,{}可以省略,若有返回值,则若想去掉{},则必须同时省略return,且执行语句也保证只有一句
  5. Lambda表达式不会生成单独的内部类文件

代码演示1

package cn.itcast.demo;
public class LambdaDemo {
    public static void main(String[] args) {
        //匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程1执行了........");
            }
        };
        new Thread(runnable).start();

        //使用lambda表达式,如果方法体中只有一行代码的话,可以将大括号省略掉
        Runnable runnable2 = ()->System.out.println("子线程2执行了.......");
        new Thread(runnable2).start();

        //最简形式
        new Thread(()->System.out.println("子线程3执行了.......")).start();
    }
}

代码演示2

package cn.itcast.demo;
import java.util.Comparator;
import java.util.TreeSet;
public class LambdaDemo2 {
    public static void main(String[] args) {
        //匿名内部类
        Comparator<String> com = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length() - o2.length();
            }
        };
        TreeSet<String> ts = new TreeSet<String>(com);

        //Lambda表达式
        Comparator<String> com2 = (String o1, String o2)->{
            return o1.length()-o2.length();
        };
        TreeSet<String> ts2 = new TreeSet<String>(com2);

        Comparator<String> com3 = (o1, o2) -> o1.length()-o2.length();
        TreeSet<String> ts3 = new TreeSet<String>(com3);
    }
}

函数式接口

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

那么如何判断一个接口是否是函数式接口呢?
可以使用这个注解

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

代码演示

package cn.itcast.demo;
//函数式接口
@FunctionalInterface
public interface Usb {
    void service();
}

LambdaDemo3

package cn.itcast.demo;
public class LambdaDemo3 {
    public static void main(String[] args) {
        //匿名内部类
        Usb mouse = new Usb() {
            @Override
            public void service() {
                System.out.println("鼠标开始工作了........");
            }
        };
        run(mouse);

        //Lambda表达式
        Usb fan = ()->System.out.println("风扇开始工作了.......");
        run(fan);
    }
    public static void run(Usb usb){
        usb.service();
    }
}

常见的函数式接口

函数式接口 参数类型 返回类型 说明
Consumer T void void accept(T t); 对类型T的对象应用操作
Suppiler T T get(); 返回类型为T的对象
Function<T,R> T R R apply(T t); 对类型为T的对象应用操作,并返回类型为R类型的对象
Predicate T boolean boolean test(T t); 确定类型为T的对象是否满足条件,并返回boolean类型

除了表格中的这几个函数式接口,Runnable、Comparator等也属于函数式接口。

package cn.itcast.demo;
import java.util.ArrayList;
import java.util.Arrays;
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;
public class LambdaDemo4 {
    public static void main(String[] args) {
        //匿名内部类
        Consumer<Double> consumer = new Consumer<Double>() {
            @Override
            public void accept(Double t) {
                System.out.println("聚餐消费"+t);
            }
        };
        happy(consumer, 1000);

        //Lambda表达式
        Consumer<Double> consumer2 = t->System.out.println("聚餐消费"+t);
        happy(consumer2, 1200);
        happy(t->System.out.println("唱歌消费"+t),2000);
        System.out.println("--------------------------");

        int[] arr = getNums(() -> new Random().nextInt(100), 5);
        System.out.println(Arrays.toString(arr));
        System.out.println("--------------------------");

        String str = handlerString(s -> s.toUpperCase(), "hello");
        System.out.println(str);
        System.out.println("--------------------------");

        List<String> names = new ArrayList<String>();
        names.add("zhangsan");
        names.add("zhangxiaohua");
        names.add("lisi");
        names.add("wangwu");
        List<String> result = filterNames(s -> s.startsWith("zhang"), names);
        System.out.println(result.toString());

        List<String> result2 = filterNames(s -> s.length()>5, names);
        System.out.println(result2.toString());
    }
    //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 < count; i++ ){
            arr[i] = supplier.get();
        }
        return arr;
    }
    //Function 函数型接口
    public static String handlerString(Function<String, String> function, String str){
        return function.apply(str);
    }
    //Predicate 断言型接口
    public static List<String> filterNames(Predicate<String> predicate, List<String> list){
        List<String> resultList = new ArrayList<String>();
        for(String str : list){
            if(predicate.test(str)){
                resultList.add(str);
            }
        }
        return resultList;
    }
}

运行结果
在这里插入图片描述

方法引用

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

常见形式:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new

代码演示

package cn.itcast.demo;
import java.util.Comparator;
import java.util.function.Consumer;
//方法引用
public class LambdaDemo5 {
    public static void main(String[] args) {
        //对象::实例方法
        Consumer<String> consumer = s->System.out.println(s);
        consumer.accept("hello");
        //使用方法引用
        Consumer<String> consumer2 = System.out::println;
        consumer2.accept("world");

        //类::静态方法
        Comparator<Integer> com = (o1, o2)->Integer.compare(o1, o2);
        Comparator<Integer> com2 = Integer::compare;

        //.....
    }
}

流(Stream)

流中保存对集合或数组数据的操作。和集合类似,但是集合中保存的是数据,而流中保存的是操作。
在这里插入图片描述
Stream的特点

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

Stream的使用步骤

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

创建Stream

  • 通过Collection对象的stream()方法或parallelStream()方法
  • 通过Arrays的stram()方法
  • 通过Stream接口的of()、iterator()、generate()方法

代码演示

package cn.itcast.demo2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.Stream;
public class StreamDemo {
    public static void main(String[] args) {

        //通过Collection对象的stream()方法或parallelStream()方法
        ArrayList<String> al = new ArrayList<String>();
        al.add("apple");
        al.add("huawei");
        al.add("xiaomi");
        Stream<String> stream = al.stream();
        //遍历
        stream.forEach(s->System.out.println(s));
        System.out.println("----------------------");

        //通过Arrays的stram()方法
        String[] arr = {"aaa", "bbb", "ccc"};
        Stream<String> stream2 = Arrays.stream(arr);
        stream2.forEach(s->System.out.println(s));
        System.out.println("----------------------");

        //通过Stream接口的of()、iterator()、generate()方法
        Stream<Integer> stream3 = Stream.of(10, 20, 30, 40);
        stream3.forEach(System.out::println);
        System.out.println("-----------迭代流-----------");
        Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
        iterate.limit(10).forEach(System.out::println);
        System.out.println("-----------生成流-----------");
        Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
        generate.limit(10).forEach(System.out::println);
    }
}

中间操作

  • filter、limit、skip、distinct、sorted
  • map
  • parallel

代码演示

package cn.itcast.demo2;
import java.util.ArrayList;
public class StreamDemo2 {
    public static void main(String[] args) {
        ArrayList<Student> al = new ArrayList<Student>();
        al.add(new Student("zhangsan",8000));
        al.add(new Student("lisi",12000));
        al.add(new Student("wangwu",25000));
        al.add(new Student("zhouqi",5000));
        al.add(new Student("zhouqi",5000));
        //中间操作1
        //filter 过滤
        System.out.println("----------filter---------");
        al.stream().filter(stu->stu.getSalary()>10000).forEach(System.out::println);
        //limit 限制
        System.out.println("----------limit---------");
        al.stream().limit(2).forEach(System.out::println);
        //skip 跳过
        System.out.println("----------skip---------");
        al.stream().skip(2).forEach(System.out::println);
        //distinct 去重复
        System.out.println("----------distinct---------");
        al.stream().distinct().forEach(System.out::println);

        //sorted 排序
        al.stream().sorted((stu1,stu2)->Double.compare(stu1.getSalary(),stu2.getSalary()))
                .forEach(System.out::println);

        //中间操作2 map
        System.out.println("----------map---------");
        al.stream().map(stu->stu.getName()).forEach(System.out::println);

        //中间操作3 parallel 采用多线程效率
        System.out.println("----------parallel---------");
        al.parallelStream().forEach(System.out::println);
    }
}

串行流和并行流的区别

package cn.itcast.demo2;
import java.util.ArrayList;
import java.util.UUID;
public class StreamTest {
    public static void main(String[] args) {

        //串行流和并行流的区别
        ArrayList<String> list = new ArrayList<String>();
        for(int i = 0; i < 5000000; i++){
            list.add(UUID.randomUUID().toString());
        }
        //并行流 10s 并行
        long start = System.currentTimeMillis();
        long count = list.parallelStream().sorted().count();
        System.out.println(count);
        long end = System.currentTimeMillis();
        System.out.println("用时:"+(start-end));
    }
}

终止操作

  • forEach、min、max、count
  • reduce、collect

代码演示

package cn.itcast.demo2;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class StreamDemo3 {
    public static void main(String[] args) {
        ArrayList<Student> al = new ArrayList<Student>();
        al.add(new Student("zhangsan",8000));
        al.add(new Student("lisi",12000));
        al.add(new Student("wangwu",25000));
        al.add(new Student("zhouqi",5000));
        al.add(new Student("zhouqi",5000));

        //终止操作 forEach
        al.stream().filter(e->{
            System.out.println("过滤了......");
            return e.getSalary()>10000;
        }).forEach(System.out::println);
        //min max count
        System.out.println("---------min---------");
        Optional<Student> min = al.stream()
                .min((stu1, stu2) -> Double.compare(stu1.getSalary(), stu2.getSalary()));
        System.out.println(min.get());

        System.out.println("---------max---------");
        Optional<Student> max = al.stream()
                .min((stu1, stu2) -> Double.compare(stu1.getSalary(), stu2.getSalary()));
        System.out.println(max.get());

        System.out.println("---------count---------");
        long count = al.stream().count();
        System.out.println("学生人数:"+count);

        //终止操作 reduce 规约
        //计算所有工资
        System.out.println("---------reduce---------");
        Optional<Double> sum = al.stream().map(stu -> stu.getSalary()).reduce((x, y) -> x + y);
        System.out.println(sum.get());

        //终止操作 collect 收集
        //获取所有学生姓名,封装一个list集合
        System.out.println("---------collect---------");
        List<String> names = al.stream().map(stu -> stu.getName()).collect(Collectors.toList());
        for(String name : names){
            System.out.println(name);
        }
    }
}

新的日期 API

之前的日期API存在问题:线程安全问题、设计混乱

演示线程安全问题

package cn.itcast.demo3;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
//演示线程安全问题
public class DateDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        ExecutorService pool = Executors.newFixedThreadPool(10);
        Callable<Date> callable = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return sdf.parse("20200425");
            }
        };
        List<Future<Date>> list = new ArrayList<>();
        for(int i = 0; i < 10; i++){
            Future<Date> future = pool.submit(callable);
            list.add(future);
        }
        for(Future<Date> future : list){
            System.out.println(future.get());
        }
        pool.shutdown();
    }
}

本地化时间 API

  • LocalDate
  • LocatTime
  • LocalDateTime
  • Instant:时间戳
  • ZoneId:时区

代码演示

package cn.itcast.demo3;
import java.time.LocalDateTime;
public class LocalDateTimeDemo {
    public static void main(String[] args) {

         //创建本地时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        System.out.println(ldt.getYear());
        System.out.println(ldt.getMonthValue());
        System.out.println(ldt.getDayOfMonth());

        //添加两天
        LocalDateTime newDate = ldt.plusDays(2);
        System.out.println(newDate);

        //减少一个月
        LocalDateTime newDate2 = ldt.minusMinutes(1);
        System.out.println(newDate2);
    }
}

代码演示2

package cn.itcast.demo3;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Set;
public class InstantDemo {
    public static void main(String[] args) {

         //创建
        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());

        //3.ZoneId 时区
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for(String str : availableZoneIds){
            System.out.println(str);
        }
    }
}

Date、Instant、LocalDateTime的转换

package cn.itcast.demo3;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
public class TranferDemo {
    public static void main(String[] args) {

        //Date--->Instant--->LocalDateTime
        Date date = new Date();
        Instant instant = date.toInstant();
        System.out.println(instant);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        System.out.println(localDateTime);
        System.out.println("----------------------------");

        //LocalDateTime--->Instant--->Date
        Instant instant2 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        System.out.println(instant2);
        Date date2 = Date.from(instant2);
        System.out.println(date2);
    }
}

DateTimeFormatter:格式化类

package cn.itcast.demo3;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DataTimeFormatterDemo {
    public static void main(String[] args) {

        //创建DateTimeFormatter对象
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        //格式化时间字符串
        String format = dtf.format(LocalDateTime.now());
        System.out.println(format);
        //将字符串解析成时间
        LocalDateTime localDateTime = LocalDateTime.parse("2020-03-01 10:20:35", dtf);
        System.out.println(localDateTime);
    }
}

本文地址:https://blog.csdn.net/weixin_45620489/article/details/107287417

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网