欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

2020年了,你还不知道JAVA8新特性??

程序员文章站 2024-01-17 14:24:52
Java8新特性lambda表达式在JDK8之前,一个方法能接受的参数都是变量,例如: object.method(Object o)那么,如果需要传入一个动作呢?比如回调。那么你可能会想到匿名内部类。//传统方式:interface Printer{ public void printer(integer id);}class Operation(){public static void create(integer id,Printer printer){ p...

Java8新特性

lambda表达式

在JDK8之前,一个方法能接受的参数都是变量,例如: object.method(Object o)
那么,如果需要传入一个动作呢?比如回调。
那么你可能会想到匿名内部类。

//传统方式:
interface Printer{
    public void printer(integer id);
}
class Operation(){
		public static void create(integer id,Printer printer){
		     printer.printer(id);
		}
}
class demo{
	public static void main(String[] args) {
		Operation operation=new Operation();
		int id=1;
		//匿名内部类
		operation.create(i,new Printer(){
			 public void printer(integer id){
			   System.out.println("id:"+id);
			 }
		});
	}
}

Printer其实就是一种动作,但是我们真正关心的只有printer方法里的内容而已,我们用Lambda
表示,可以将上面的代码就可以优化成

//Lambda
public static void main(String[] args) {
		Operation operation=new Operation();
		int id=1;
		operation.create(id, x->System.out.println("id:"+x));
	}

如果我们的接口方法定义不带任何参数,则可以用空括号替换:

()->  System.out.println("anything you wan to print")

注意:

  • 即使没有在箭头的左侧指定参数的类型,编译器也会从接口方法的形式参数中推断出其类型
  • 当只有一个参数的时候,我们完全可以省略参数的括号
  • 当函数体只有一行的时候,我们完全可以省略函数体花括号

函数式接口

函数式接口是新增的一种接口定义。
用**@FunctionalInterface修饰的接口叫做函数式接口**,或者,函数式接口就是一个只具有一个抽象方法的普通接口,@FunctionalInterface可以起到校验的作用。

Java8中提供给我们这么多函数式接口就是为了让我们写Lambda表达式更加方便,当然遇到特殊情况,你还是需要定义你自己的函数式接口然后才能写对应的Lambda表达式。
总的来说,如果没有函数式接口,就不能写Lambda表达式。

接口的默认方法和静态方法

在接口中用default修饰的方法称为默认方法
接口中的默认方法一定要有默认实现(方法体),接口实现者可以继承它,也可以覆盖它。

    default String methodDefault(String s) {
        System.out.println("lol");
    }

方法引用

  • 实例对象::实例方法名

  • 类名::静态方法名

  • 类名::实例方法名

  • 引用构造方法

  • 引用数组

          // 引用方法1   实例对象::实例方法名
            // System.out代表的就是PrintStream类型的一个实例,println是这个实例的一个方法
    //        Consumer<String> consumer1 = s -> System.out.println(s);
            Consumer<String> consumer2 = System.out::println;
            consumer2.accept("呵呵");
     
            // 引用方法2   类名::静态方法名
            // Function中的唯一抽象方法apply方法参数列表与abs方法的参数列表相同,都是接收一个Long类型参数。
    //        Function<Long, Long> f = x -> Math.abs(x);
            Function<Long, Long> f = Math::abs;
            Long result = f.apply(-3L);
     
            // 引用方法3  类名::实例方法名
            // 若Lambda表达式的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,就可以使用这种方法
    //        BiPredicate<String, String> b = (x,y) -> x.equals(y);
            BiPredicate<String, String> b = String::equals;
            b.test("a", "b");
            // 引用构造方法
            // 在引用构造方法的时候,构造方法参数列表要与接口中抽象方法的参数列表一致,格式为 类名::new
    //        Function<Integer, StringBuffer> fun = n -> new StringBuffer(n);
            Function<Integer, StringBuffer> fun = StringBuffer::new;
            StringBuffer buffer = fun.apply(10);
    
      // 引用数组
            // 引用数组和引用构造器很像,格式为 类型[]::new,其中类型可以为基本类型也可以是类
    //        Function<Integer, int[]> fun = n -> new int[n];
            Function<Integer, int[]> fun1 = int[]::new;
            int[] arr = fun1.apply(10);
            Function<Integer, Integer[]> fun2 = Integer[]::new;
            Integer[] arr2 = fun2.apply(10);
    
    
  • 实例对象::实例方法名
    

引入了stream流(管道流)

Stream 是在 Java8 新增的特性,普遍称其为流;它不是数据结构也不存放任何数据,其主要用于集合的逻辑处理。Stream是对集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者打批量数据操作

这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选、排序、聚合等。
和以前的collection操作不同,Stream操作还有两个基础的特征:
Pipelining:中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格。这样做可以对操作进行优化,比如延迟执行和短路。
内部迭代:以前对集合遍历都是通过Iterator或者ForEach的方式,显示的在集合外部进行迭代,这叫做外部迭代。Stream提供了内部迭代的方式,通过访问者模式实现。并行流parallelStream

Stream管道流的基本操作

  • 源操作:可以将数组、集合类、行文本文件转换成管道流Stream进行数据处理
  • 中间操作:对Stream流中的数据进行处理,比如:过滤、数据转换等等
  • 终端操作:作用就是将Stream管道流转换为其他的数据类型。这部分我们还没有讲,我们后面章节再介绍。

管道的功能包括:Filter(过滤)、Map(映射)、sort(排序)等,集合数据通过Java Stream管道处理之后,转化为另一组集合或数据输出。

2020年了,你还不知道JAVA8新特性??
List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");

List<String> list = nameStrs.stream()
        .filter(s -> s.startsWith("L"))
        .map(String::toUpperCase)
        .sorted()
        .collect(toList());
System.out.println(list);
  • 首先,我们使用Stream()函数,将一个List转换为管道流

  • 调用filter函数过滤数组元素,过滤方法使用lambda表达式,以L开头的元素返回true被保留,其他的List元素被过滤掉

  • 然后调用Map函数对管道流中每个元素进行处理,字母全部转换为大写

  • 然后调用sort函数,对管道流中数据进行排序

  • 最后调用collect函数toList,将管道流转换为List返回

    将数组转换为管道流

    使用Stream.of()方法,将数组转换为管道流。

    String[] array = {"Monkey", "Lion", "Giraffe", "Lemur"};
    Stream<String> nameStrs2 = Stream.of(array);
    
    Stream<String> nameStrs3 = Stream.of("Monkey", "Lion", "Giraffe", "Lemur");
    

    将集合类对象转换为管道流

    通过调用集合类的stream()方法,将集合类对象转换为管道流。

    List<String> list = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");
    Stream<String> streamFromList = list.stream();
    
    Set<String> set = new HashSet<>(list);
    Stream<String> streamFromSet = set.stream();
    

    将文本文件转换为管道流

    通过Files.lines方法将文本文件转换为管道流,下图中的Paths.get()方法作用就是获取文件,是Java NIO的API!

    也就是说:我们可以很方便的使用Java Stream加载文本文件,然后逐行的对文件内容进行处理。

    Stream<String> lines = Files.lines(Paths.get("file.txt"));
    

    参考:具体可以参考这个写的很详细,很棒

    Stream总结

    不是数据结构,它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据
    它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素
    所有 Stream 的操作必须以 lambda 表达式为参数
    惰性化,很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始,Intermediate操作永远是惰性化的
    当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的
    

Date/Time API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。对日期与时间的操作一直是Java程序员最痛苦的地方之一。标准的 java.util.Date以及后来的java.util.Calendar一点没有改善这种情况(可以这么说,它们一定程度上更加复杂)。
这种情况直接导致了Joda-Time——一个可替换标准日期/时间处理且功能非常强大的Java API的诞生。Java 8新的Date-Time API (JSR 310)在很大程度上受到Joda-Time的影响,并且吸取了其精髓。
LocalDate类

    /**
     * LocaleDate只持有ISO-8601格式且无时区信息的日期部分
     */
    public static void testLocaleDate() {
        LocalDate date = LocalDate.now(); // 当前日期
 
        date = date.plusDays(1); // 增加一天
        date = date.plusMonths(1); // 减少一个月
        date = date.minusDays(1); // 减少一天
        date = date.minusMonths(1); // 减少一个月
        System.out.println(date);
    }

LocalTime类

    /**
     * LocaleTime只持有ISO-8601格式且无时区信息的时间部分
     */
    public static void testLocaleTime() {
        LocalTime time = LocalTime.now(); // 当前时间
        time = time.plusMinutes(1); // 增加一分钟
        time = time.plusSeconds(1); // 增加一秒
        time = time.minusMinutes(1); // 减少一分钟
        time = time.minusSeconds(1); // 减少1秒
        System.out.println(time);
    }

LocalDateTime类

    /**
     * LocaleDateTime把LocaleDate与LocaleTime的功能合并起来,它持有的是ISO-8601格式无时区信息的日期与时间
     */
    public static void testLocalDateTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime); // UTC格式
        System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // 自定义格式
 
        // 原有方法
//        Date nowDate = new Date();
//        System.out.println(nowDate);
//        System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").format(nowDate));
    }

ZoneDateTime类

    /**
     * ZonedDateTime持有ISO-8601格式,具有时区信息的日期与时间。
     */
    public static void testZonedDateTime() {
        ZonedDateTime zonedDateTime =  ZonedDateTime.now();
        System.out.println(zonedDateTime);
 
        ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
        System.out.println(zonedDatetimeFromZone);
 
        ZoneId zoneId = ZoneId.systemDefault();
        System.out.println(zoneId);
    }

Clock类

    /**
     * 它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。
     * Clock可以替换System.currentTimeMillis()与TimeZone.getDefault()
     */
    public static void testClock() {
        Clock utc = Clock.systemUTC(); // 世界标准时间
        System.out.println(LocalDateTime.now(utc));
 
        Clock shanghai = Clock.system(ZoneId.of("Asia/Shanghai")); // 上海时间
        System.out.println(LocalDateTime.now(shanghai));
    }

Duration类

    /**
     * Duration使计算两个日期间的不同变的十分简单。
     */
    public static void testDuration() {
        final LocalDateTime from = LocalDateTime.parse("2019-07-15 18:50:50", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        final LocalDateTime to = LocalDateTime.parse("2019-07-16 19:50:50", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        final Duration duration = Duration.between(from, to);
        System.out.println("Duration in days: " + duration.toDays()); // 1
        System.out.println("Duration in hours: " + duration.toHours()); // 25
    }

本文地址:https://blog.csdn.net/weixin_41185826/article/details/107256555