Java16都快上线了,你该不会连Java8的特性都不会用吧?

简介: 2020年,Java16有了新的消息,预计将在2021年的3月16日正式发布。但是这一消息对于百分之九十的国内程序员来说都只是一个新闻而已,因为国内的绝大部分公司依然使用着Java8。这款发布于2014年的JDK版本深受各大公司的喜爱,最大的原因取决于它的稳定性。即使如此,依然有一半以上的程序员对于Java8的特性不了解,于是我用一个周末的时间把JDK8的”新“特性肝了一遍,希望对大家有所帮助。

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)前言


2020年,Java16有了新的消息,预计将在2021年的3月16日正式发布。但是这一消息对于百分之九十的国内程序员来说都只是一个新闻而已,因为国内的绝大部分公司依然使用着Java8。这款发布于2014年的JDK版本深受各大公司的喜爱,最大的原因取决于它的稳定性。


即使如此,依然有一半以上的程序员对于Java8的特性不了解,于是我用一个周末的时间把JDK8的”新“特性肝了一遍,希望对大家有所帮助。


(二)Lambda表达式


Lambda是一个匿名函数,它允许你通过表达式来代替功能接口,使用lambda可以让代码变得更加简洁。简单来讲,lambda使用更简洁的方式给接口添加实现方法。


Lambda只能在函数式接口中使用,函数式接口就是那些只有一个抽象方法的接口,可以用注解@FunctionalInterface修饰,如果一个接口中有多个方法,就不能再使用Lambda了。


我们常用的Runnable、Comparator都是函数式接口:


网络异常,图片无法展示
|

网络异常,图片无法展示
|


lambda的语法格式如下:



(parameters) ->expression(parameters) ->{ statements; }

2.1 无参数、无返回值


lambda实现的是对功能接口代码的简洁化,比如下面这一段:


Runnablerunnable=newRunnable() {
@Overridepublicvoidrun() {
System.out.println("run");
    }
};

我们在创建一个Runnable对象的时候需要通过匿名内部类实现接口中定义的方法,而使用lambda表达式,上面的代码一行就可以搞定:


Runnablerunnable2= () ->System.out.println("run");

2.2 有参数,无返回值


我们先写一个这样的接口:


publicinterfaceStudent {
publicvoidgetAge(intage);
}

在以前的代码中,我们需要首先写一个类去继承这个接口,或者是写一个匿名内部类,如:


Studentstudent=newStudent() {
@OverridepublicvoidgetAge(intage) {
System.out.println(age);
    }
};

现在就变得简单了:


Studentstudent2=(age) -> { System.out.println(age); };

如果只有一个参数,小括号可以不写:


Studentstudent3=age-> { System.out.println(age); };

2.3 有参数,有返回值


写一个接口:


publicinterfaceStudent {
publicintgetAge(intage);
}

直接写lambda表达式了:


Studentstudent5=age-> { returnage; };
System.out.println(student5.getAge(1));

(三)内置函数式接口


在前面已经介绍了什么是函数式接口,函数式接口就是那些只有一个抽象方法的接口,Java8中内置了四种函数式接口:


Consumer<T> : voidaccept(Tt);
Supplier<T> : Tget();
Function<T,R> : Rapply(Tt);
Predicate<T> : booleantest(Tt)

这四种接口和我们平常写的没有什么区别,可以在Java8中直接调用:


3.1 Consumer


消费型接口,提供了一个参数、无返回值的接口方法,就和消费一样,花出去就没有了。


publicstaticvoidmain(String[] args) {
consume(100,money-> {
System.out.println("消费了"+money+"元");
    });
}
publicstaticvoidconsume(doublemoney, Consumer<Double>consumer){
consumer.accept(money);
}

3.2 Supplier


供给型接口,提供了无参数,有返回值的接口方法,主要起到供给数据的作用,比如实现一个生成随机数的功能:


publicstaticvoidmain(String[] args) {
System.out.println(getRandomNum(()->(int)(Math.random()*100)));
}
publicstaticintgetRandomNum(Supplier<Integer>supplier){
returnsupplier.get();
}

3.3 Function


函数型接口,提供带参数和返回值的接口方法,可用来对数据进行处理后再返回,比如实现一个替换字符串给功能:


publicstaticvoidmain(String[] args) {
//去掉前后空格System.out.println(handlerString("\t\tJava鱼仔\t\t",(str)->str.trim()));
}
publicstaticStringhandlerString(Stringstring, Function<String,String>function){
returnfunction.apply(string);
}

3.4 Predicate


断言型接口,提供带参数和返回值的接口方法,只不过返回值是boolean类型,可用于进行判断,比如实现一个判断某个字符串是否是整数的需求


publicstaticvoidmain(String[] args) {
Patternpattern=Pattern.compile("^[-\\+]?[\\d]*$");
if (isDigit("111",s-> {
returnpattern.matcher(s).matches();
     })){
System.out.println("is Digit");
     }
}
publicstaticStringhandlerString(Stringstring, Function<String,String>function){
returnfunction.apply(string);
}

(四)Stream API


Java8中两个最重大的改变,一个是Lambda表达式,另外一个就是Stream API


Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。


使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。


Stream的执行过程分为三步


1、创建stream


2、操作stream(查找、筛选、过滤等等)


3、执行stream


stream的操作属于惰性求值,即所有的操作是在执行stream时一次性执行。


4.1 创建stream


创建流的方式有四种,这里直接把创建方式的注释写进代码里


publicstaticvoidmain(String[] args) {
//创建Stream//1、通过Collection系列集合提供的stream()或parallelStream()List<String>list=newArrayList<>();
Stream<String>stream=list.stream();
//2、通过Arrays中的静态方法stream()获取Integer[] integers=newInteger[10];
Stream<Integer>stream1=Arrays.stream(integers);
//3、通过Stream类中的静态方法of()Stream<Integer>stream2=Stream.of(integers);
//4、迭代创建Stream<Integer>stream3=Stream.iterate(0, (x) ->x+2);
}

4.2 操作stream


stream有多种操作集合的方法,下面一一进行讲解:


为了更方便的演示,新建一个实体类User:


publicclassUser {
privateStringname;
privateintage;
privateStringsex;
//这里省略构造方法、get、set、toString方法}

filter过滤--通过某种条件过滤元素:


filter通过Predicate接口过滤元素,下面这段代码将年龄超过30岁的过滤出来


publicstaticvoidmain(String[] args) {
List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
newUser("王五",33,"female")
    );
//过滤出年龄大于30岁的人Stream<User>userStream=list.stream().filter((e) ->e.getAge() >=30);
userStream.forEach((e)->System.out.println(e));
}

limit截断--使元素不超过给定的数量


//对取出来的数据只展示一条Stream<User>userStream=list.stream()
        .filter((e) ->e.getAge() >=30)
        .limit(1);
userStream.forEach((e)->System.out.println(e));

skip--跳过集合中的前n个数


可以和limit联合使用取出指定的范围的数


Stream<User>userStream=list.stream().skip(2);

distinct--去重,通过元素的hashcode()和equals()去除重复元素


去重是根据hashcode()和equals()方法判断重复元素的,因此实体类了需要重写hashcode()和equals()方法


Stream<User>userStream=list.stream().distinct();


map--通过Function接口对stream中的每个数据处理后返回新的数据


比如我想把所有的英文改为大写,就可以这样


List<String>list1=Arrays.asList("aa","bb","cc");
Stream<String>stringStream=list1.stream().map((str) ->str.toUpperCase());
stringStream.forEach((e)->System.out.println(e));


flatmap--通过Function接口把stream的每一个值都换成另外个stream,最后再把所有stream连接成一个stream


这个方法的使用可能会比较难懂,通过一个例子,把包含三个字符串的集合中的每个字符串都分成一个个字符提取出来。比如把一个集合{"aa","bb","cc"}变成{'a','a','b','b','c','c'},使用map就需要这样:


List<String>list1=Arrays.asList("aa","bb","cc");
Stream<Stream<Character>>streamStream=list1.stream().map((str) -> {
List<Character>characters=newArrayList<>();
for (Characterch : str.toCharArray()) {
characters.add(ch);
    }
returncharacters.stream();
});
streamStream.forEach((stream)->{
stream.forEach((character->System.out.println(character)));
});


它第一个stream的返回值是stream中套一个字符流,输出的时候也需要先遍历最外层的stream再遍历内层的stream,比较麻烦,于是就可以使用flatmap,他会把多个stream合并为一个。


Stream<Character>characterStream=list1.stream().flatMap((str) -> {
List<Character>characters=newArrayList<>();
for (Characterch : str.toCharArray()) {
characters.add(ch);
    }
returncharacters.stream();
});
characterStream.forEach((e)->System.out.println(e));

sorted--自然排序,按照Comparable方式排序


Stream<String>stringStream=list.stream().sorted();

sorted(Comparator comparator)--定制排序,自己写一个Comparator 实现排序


List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
);
Stream<User>sorted=list.stream().sorted((e1, e2) -> {
returne1.getAge() ==e2.getAge() ?0 : e1.getAge() >e2.getAge() ?1 : -1;
});
sorted.forEach((e)->System.out.println(e));

4.3 执行stream


如果只是操作stream,流的数据是不会变化的,接下来介绍执行stream的一系列方法,首先把接下来会用的数据创建进来:


List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
);

allMatch--检查是否匹配所有元素


//判断所有的元素的sex是否都是male,这里返回falsebooleanmale=list.stream().allMatch((e) ->e.getSex().equals("male"));
System.out.println(male);

anyMatch--检查是否至少匹配一个元素


booleanmale=list.stream().anyMatch((e) ->e.getSex().equals("male"));
System.out.println(male);//这里返回true

noneMatch--检查是不是没有元素能够匹配指定的规则


booleanmale=list.stream().noneMatch((e) ->e.getSex().equals("male"));
System.out.println(male);//这里返回false

findFirst--返回第一个元素


Optional<User>first=list.stream().findFirst();
System.out.println(first.get());

count--返回当前流中的元素总个数


longcount=list.stream().count();
System.out.println(count);

max--返回当前流中的最大值


返回最大值和最小值依旧需要实现comparator接口方法


Optional<User>max=list.stream().max((e1, e2) -> {
returnInteger.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

min--返回当前流中的最小值


Optional<User>max=list.stream().min((e1, e2) -> {
returnInteger.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

reduce--规约,将流中的元素反复结合起来,得到一个值


List<Integer>list=Arrays.asList(1,2,3,4,5,6,7,8,9);
//从第0个元素开始,对list求和Integerreduce=list.stream().reduce(0, (x, y) ->x+y);
System.out.println(reduce);

collection--收集,将流中的数据接收成其他的形式


比如我们把上面User数据的名字收集到List数组中:


List<String>collect=list.stream().map((e) ->e.getName()).collect(Collectors.toList());
System.out.println(collect);

Collectors提供了大量的转化为其他方式的实现,这里不做过多介绍。


(五)接口中的默认方法和静态方法


在1.8之前,接口中的方法只能声明无法实现,在Java8中,接口中可以添加默认方法和静态方法了。


首先介绍默认方法,通过default修饰的方法可以在接口中增加实现。



publicinterfaceMyInterface {
defaultvoiddefaultMethod(){
System.out.println("hello");
    }
}

另外是接口中的静态方法:


publicinterfaceMyInterface {
publicstaticvoidstaticMethod(){
System.out.println("hello");
    }
}

(六)新时间日期API


JAVA8中增加了新的时间日期API,通过代码来混个眼熟:


6.1 LocalDate、LocalTime、LocalDateTime


@Testpublicvoidtest1(){
//获取当前时间LocalDateTimelocalDateTime=LocalDateTime.now();
System.out.println(localDateTime);
//增加两年System.out.println(localDateTime.plusYears(2));
//减少两年System.out.println(localDateTime.minusYears(2));
//获取年、月、日、小时、分钟、秒System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMinute());
System.out.println(localDateTime.getSecond());
}

6.2 Instant :时间戳


@Testpublicvoidtest2(){
Instantinstant=Instant.now();
//获取当前时间戳System.out.println(instant.toEpochMilli());
}

6.3 Duration :计算两个时间间隔


@Testpublicvoidtest3(){
Instantinstant1=Instant.now();
try {
Thread.sleep(1000);
    } catch (InterruptedExceptione) {
e.printStackTrace();
    }
Instantinstant2=Instant.now();
Durationbetween=Duration.between(instant1, instant2);
//计算出两个日期相差的毫秒、分钟、小时等数据System.out.println(between.toMillis());
System.out.println(between.toMinutes());
System.out.println(between.toHours());
}

6.4 Period:计算两个日期间隔


@Testpublicvoidtest4(){
LocalDatelocalDate1=LocalDate.of(2020,11,1);
LocalDatelocalDate2=LocalDate.now();
Periodbetween=Period.between(localDate1, localDate2);
//计算相差几年几个月零几天System.out.println(between.getYears());
System.out.println(between.getMonths());
System.out.println(between.getDays());
}

6.5 TemporalAdjuster:时间矫正器


TemporalAdjuster用于对时间进行操作,我们可以通过TemporalAdjusters这个类调用大量对时间操作的方法,比如下个周日等等。


@Testpublicvoidtest5(){
LocalDateTimelocalDateTime=LocalDateTime.now();
LocalDateTimewith=localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(with);
}

6.6 格式化时间


时间格式化类在JAVA8之前用的最多的就是SimpleDateFormat,现在多了一个叫做DateTimeFormatter的格式化类:


@Testpublicvoidtest6(){
DateTimeFormatterdtf=DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDateTimelocalDateTime=LocalDateTime.now();
System.out.println(localDateTime.format(dtf));
}

(七)总结


总的来讲,Java8的新东西还是有很多的,虽然现在很多程序员都不习惯使用新的语法,但对这些新语法也不要抗拒,毕竟现在最新的Java版本已经到16了呢!

相关文章
|
2月前
|
安全 前端开发 Java
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择。依赖注入使对象管理交由Spring容器处理,实现低耦合高内聚;AOP则分离横切关注点如事务管理,增强代码模块化。Spring还提供MVC、Data、Security等模块满足多样需求,并通过Spring Boot简化配置与部署,加速微服务架构构建。掌握这些核心概念与工具,开发者能更从容应对挑战,打造卓越应用。
35 1
|
2月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
71 0
|
4天前
|
安全 Java API
java安全特性
java安全特性
19 8
|
4天前
|
JavaScript 前端开发 Java
Java 8 新特性详解及应用示例
Java 8 新特性详解及应用示例
|
5天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。
|
14天前
|
机器学习/深度学习 人工智能 安全
python和Java的区别以及特性
Python:适合快速开发、易于维护、学习成本低、灵活高效。如果你需要快速上手,写脚本、数据处理、做点机器学习,Python就是你的首选。 Java:适合大型项目、企业级应用,性能要求较高的场景。它类型安全、跨平台能力强,而且有丰富的生态,适合更复杂和规模化的开发。
18 3
|
21天前
|
安全 Java API
Java 18 概述:新特性一览
Java 18 作为 Java 平台的最新版本,引入了多项令人振奋的新特性和改进,包括模式匹配、记录类型、流库改进、外部函数与内存 API 以及并发处理增强。这些新功能不仅提升了开发者的生产力,还显著增强了 Java 的性能和安全性。本文将详细介绍 Java 18 的主要新特性,并通过代码示例帮助读者更好地理解和应用这些功能。
|
2月前
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。
|
2月前
|
Java 开发者
Java 8新特性之Lambda表达式与函数式接口
【7月更文挑战第59天】本文将介绍Java 8中的一个重要新特性——Lambda表达式,以及与之密切相关的函数式接口。通过对比传统的匿名内部类,我们将探讨Lambda表达式的语法、使用方法和优势。同时,我们还将了解函数式接口的定义和用途,以及如何将Lambda表达式应用于函数式编程。
|
2月前
|
分布式计算 Java API
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率。流处理采用声明式编程模型,通过filter、map等操作简化数据集处理,提高代码可读性。Lambda表达式支持轻量级函数定义,配合Predicate、Function等接口,使函数式编程无缝融入Java。此外,Optional类及新日期时间API等增强功能,让开发者能更优雅地处理潜在错误,编写出更健壮的应用程序。
26 1
下一篇
无影云桌面