JDK13,不如温习下Java8
JDK13于9月17号正式GA,版本新特性可参考: https://www.oschina.net/news/109934/jdk-13-released
虽然JDK更新迅速,但开发者貌似并不买账,据统计,目前仍以JDK8使用最多,预计可能还会延续好长一段时间。虽然JDK版本已至13,但对Java8的新特性,掌握程度如何呢?
本文对Java8的主要特性进行了梳理。供温习参考。
1. 接口默认方法
以前的接口只允许有抽象方法(没有实现体),java8中提供了接口默认方法支持,即可以提供方法的默认实现,实现类可以直接继承,也可以覆盖。默认方法主要解决接口的修改导致现有实现类不兼容的问题。
@RunWith(SpringRunner.class)
@SpringBootTest
public class InterfaceDefaultFunctionTest { public interface MyFunction<T> {
T func(T t); //默认方法
default int func2(T t){
return t.hashCode();
}
//静态方法
static<T> void print(T t) {
System.out.println(t);
}
} @Test
public void testInterface(){
MyFunction<String> myFunction = new MyFunction<String>(){
@Override
public String func(String s) {
return s.toUpperCase();
}
};
System.out.println(myFunction.func("abc"));
System.out.println(myFunction.func2("abc"));
LambdaTest.MyFunction.print("efg");
}
}
默认方法通过关键字 default 声明。同时也可以在接口中定义静态方法。
2. 函数式接口
函数式接口就是有且仅有一个抽象方法的接口(可以有其它非抽象方法),如1所示代码中 MyFunction 就是一个函数式接口,只有一个抽象方法 func, 其它非抽象方法如默认方法 func2, 静态方法 print 不影响其函数式接口的特性。
函数式接口可以使用注解 @FunctionalInterface 标注,该注解会去检查接口是否符合函数式接口的规范要求,不符合的话IDE会给出提示。
java中内置了一些函数式接口,
| 函数式接口 | 描述 |
|---|---|
| Consumer | 包含方法 void accept(T t), 对类型为T的对象t进行操作 |
| Supplier | 包含方法 T get(),返回类型为T的对象 |
| Function<T,R> | 包含方法 R apply(T t),对类型为T的对象进行操作,返回类型R的对象 |
| Predicat | 包含方法 boolean test(T t), 判断类型为T的对象是否满足条件 |
以及基于这些接口的其它变种或子接口,如BiConsumer<T,U>,BiFunction<T,U,R>等。还有如Runnable,Callable等接口,也属于函数式接口 —— 都只有一个抽象方法。
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u); default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
Objects.requireNonNull(after); return (l, r) -> {
accept(l, r);
after.accept(l, r);
};
}
}
3. Lambda表达式
lambda表达式实质就是一个匿名函数,在python中很常见,java到了jdk8提供了支持。
lambda表达式的格式形如: (参数) -> {方法体语句},当参数只有一个时,左边小括号可以省略,当方法体语句只有一条时,右边大括号可以省略。
Java的lambda表达式基本上是对函数式接口实现的一种简化 —— 用lambda表达式直接代替一个函数式接口的具体实现(抽象方法的实现)。当我们使用jdk8在IDE中编写1中代码时,IDE会给出提示,
匿名实现类可以用lambda表达式替换。上述代码使用lambda表达式替换可调整为,
@Test
public void testInterface(){
MyFunction<String> myFunction = s -> s.toUpperCase();
System.out.println(myFunction.func("abc"));
System.out.println(myFunction.func2("abc"));
}
lambda表达式甚至可作为方法参数传入(实质也是作为一个函数式接口的实现类实例)
@FunctionalInterface
public interface MyFunction<T> {
T func(T t);
} public void print(MyFunction<String> function, String s){
System.out.println(function.func(s));
} @Test
public void testInterface(){
//将lambda表达式作为方法参数传入
print((String s) -> s.toUpperCase(), "abc");
}
局部变量在lambda表达式中是只读的,虽可不声明为final,但无法修改。如
@Test
public void testInterface(){
int i = 1;
//lambda表达式中无法修改局部变量i,将报编译错误
print((String s) -> {i = i+10; return s.toUpperCase();}, "abc");
}
4. 方法引用
当需要使用lambda表达式时,如果已经有了相同的实现方法,则可以使用方法引用来替代lambda表达式,几种场景示例如下。
@RunWith(SpringRunner.class)
@SpringBootTest
public class FunctionReferenceTest { @Test
public void testFunctionReference() {
// 实例::实例方法
Consumer<String> consumer = s -> System.out.println(s); //lambda表达式
Consumer<String> consumer2 = System.out::println; //方法引用
consumer.accept("abc");
consumer2.accept("abc"); //类::静态方法
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y); //lambda表达式
Comparator<Integer> comparator2 = Integer::compare; //方法引用
System.out.println(comparator.compare(10, 8));
System.out.println(comparator2.compare(10, 8)); //类::实例方法, 当引用方法是形如 a.func(b)时,用类::实例方法的形式
BiPredicate<String, String> biPredicate = (a, b) -> a.equals(b); //lambda表达式
BiPredicate<String, String> biPredicate2 = String::equals; //方法引用
System.out.println(biPredicate.test("abc", "abb"));
System.out.println(biPredicate2.test("abc","abb")); //type[]::new 数组引用
Function<Integer,Integer[]> fun= n-> new Integer[n]; //lambda表达式
Function<Integer,Integer[]> fun2=Integer[]::new; //方法引用
System.out.println(fun.apply(10));
System.out.println(fun2.apply(10)); //构造器引用
Function<String,String> func = n-> new String(n); //lambda表达式
Function<String,String> func2 = String::new; //方法引用
System.out.println(func.apply("aaa"));
System.out.println(func2.apply("aaa"));
}
}
5. Stream API
Stream与lambda应该是java8最重要的两大特性。Stream 对集合的处理进行了抽象,可以对集合进行非常复杂的查找、过滤和映射等操作。提供了一种高效的且易于使用的处理数据的方式。
Stream的三个特性:
- Stream本身不会存储元素
- Stream不会改变操作对象(即集合),会返回一个新的Stream
- Stream的中间操作不会立刻执行,而是会等到需要结果的时候才执行
Java8 的Collection接口包含了两个方法 stream(), parallelStream(), 分别返回一个顺序流与一个并行流,所有Collection类型(如List, )的对象可以调用这两个方法生成流。
Java8 的Arrays类也提供了 stream(T[] array)等方法用以生成流。也可以使用静态方法 Stream.iterate() 和 Stream.generate() 来创建无限流。
Stream的中间操作包括
| 操作 | 描述 |
|---|---|
| filter(Predicate p) | 接收 Lambda , 从流中过滤出满足条件的元素 |
| distinct() | 通过hashCode() 和 equals() 去除重复元素 |
| limit(long maxSize) | 截断流,使元素的个数不超过给定数量 |
| skip(long n) | 跳过前面的n个元素,若流中元素不足n个,则返回一个空流 |
| map(Function f) | 将每个元素使用函数f执行,将其映射成一个新的元素 |
| mapToDouble(ToDoubleFunction f) | 将每个元素使用f执行,产生一个新的DoubleStream流 |
| mapToInt(ToIntFunction f) | 将每个元素使用f执行,产生一个新的IntStream流 |
| mapToLong(ToLongFunction f) | 将每个元素使用f执行,产生一个新的LongStream流 |
| flatMap(Function f) | 将流中的每个值都通过f转换成另一个流,然后把所有流连接成一个流 |
| sorted() | 按自然顺序排序,产生一个新流 |
| sorted(Comparator comp) | 根据比较器排序,产生一个新流 |
| allMatch(Predicate p) | 判断是否匹配所有元素 |
| anyMatch(Predicate p) | 判断是否匹配至少一个元素 |
| noneMatch(Predicate p) | 判断是否没有匹配任意元素 |
| findFirst() | 返回第一个元素 |
| findAny() | 返回任意一个元素 |
| reduce(T iden, BinaryOperator b) | 对流中的元素进行reduce操作,返回T类型对象 |
| reduce(BinaryOperator b) | 对流中的元素进行reduce操作,返回Optional对象 |
Stream的终止操作包括
| 操作 | 描述 |
|---|---|
| count() | 返回元素总数 |
| max(Comparator c) | 返回最大值 |
| min(Comparator c) | 返回最小值 |
| forEach(Consumer c) | 内部迭代调用Consumer操作 |
| collect(Collector c) | 将流转换为其他形式,一般通过Collectors来实现 |
Stream使用示例
@Test
public void testStream() {
List<User> list = new ArrayList<>();
//转换为List,这里没啥意义,仅做示范
List<User> users = list.stream().collect(Collectors.toList());
//转换为Set
Set<User> users1 = list.stream().collect(Collectors.toSet());
//转换为Collection
Collection<User> users2 = list.stream().collect(Collectors.toCollection(ArrayList::new));
//计数
long count = list.stream().collect(Collectors.counting());
//求和
int total = list.stream().collect(Collectors.summingInt(User::getAge));
//求平均值
double avg= list.stream().collect(Collectors.averagingInt(User::getAge));
//获取统计对象,通过该统计对象可获取最大值,最小值之类的数据
IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(User::getAge));
//将值通过","拼接
String str= list.stream().map(User::getName).collect(Collectors.joining(","));
//最大值
Optional<User> max= list.stream().collect(Collectors.maxBy(Comparator.comparingInt(User::getAge)));
//最小值
Optional<User> min = list.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getAge)));
//从累加器开始,对指定的值,这里是年龄,进行sum的reduce操作
int t =list.stream().collect(Collectors.reducing(0, User::getAge, Integer::sum));
//对转换的结果再进行处理
int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
//分组
Map<String, List<User>> map= list.stream().collect(Collectors.groupingBy(User::getName));
//根据条件进行分区
Map<Boolean,List<User>> vd= list.stream().collect(Collectors.partitioningBy(u -> u.getName().startsWith("W"))); }
6. Optional类
Optional是一个容器类,可以避免显式的null判断,基本使用示例如下
@RunWith(SpringRunner.class)
@SpringBootTest
public class OptionalTest { @Test
public void testOptional(){
// of 不允许传入null值,否则抛出NPE
Optional<Integer> optional = Optional.of(new Integer(10));
System.out.println(optional.get()); // ofNullable 允许传入null,但是直接调用get会抛出NoSuchElementException异常,
// 可通过isPresent判断是否存在值
Optional<Integer> optional1 = Optional.ofNullable(null);
if(optional1.isPresent()) {
System.out.println(optional1.get());
}else{
System.out.println("optional1 is empty");
}
// orElse 判断是否存在值,存在则返回,不存在则返回参数里的值
Integer value = optional1.orElse(new Integer(0)); // map方法,如果optional有值,则对值进行处理返回新的Optional,
// 如果没有值则返回Optional.empty()
optional = optional.map(x -> x*x);
System.out.println(optional.get()); // 与map类似,只是要求返回值必须是Optional,进一步避免空指针
optional = optional.flatMap(x ->Optional.of(x*x));
System.out.println(optional.get()); }
}
7. Base64
在java8中,Base64成为了java类库的标准,可直接使用
import java.util.Base64; @RunWith(SpringRunner.class)
@SpringBootTest
public class Base64Test { @Test
public void testBase64(){
//base64编码
String encode = Base64.getEncoder().encodeToString("abc".getBytes());
System.out.println(encode);
//base64解码
System.out.println(new String(Base64.getDecoder().decode(encode)));
}
}
8. 日期时间类
以前的Date类是非线程安全的,并且一些常用的日期时间运算需要自己编写util工具类。java8推出了java.time包,里面包含了如 LocalDate, LocalTime, LocalDateTime等类,可方便地进行日期时间的运算,如日期间隔、时间间隔,日期时间的加减,格式化等等。
—————————————————————————————
作者:空山新雨
欢迎关注我的微信公众号:jboost-ksxy
JDK13,不如温习下Java8的更多相关文章
- WIN10下java8的开发环境配置与第一个java程序
一.开发环境配置 1.在官网上下载jdk-8u111-windows-x64.exe 2.运行安装包,可以自定义安装路径 3.进入环境变量设置: 计算机右键-->属性-->高级系统设置-- ...
- ubuntu下java8卸载
要删除 OpenJDK (如果已安装的话).首先,检查是安装的哪个 OpenJDK包. # dpkg --list | grep -i jdk 移除 openjdk包: # apt-get purge ...
- position relative top失效的问题,温习下常用两种的居中方式
因为body和html,默认高度是auto 所以相对于他们作为父元素设置position:relative的top值需要加上body,html{height:100%;} <!DOCTYPE h ...
- java8 学习系列--NIO学习笔记
近期有点时间,决定学习下java8相关的内容: 当然了不止java8中新增的功能点,整个JDK都需要自己研究的,不过这是个漫长的过程吧,以自己的惰性来看: 不过开发中不是有时候讲究模块化开发么,那么我 ...
- C语言 在VS环境下一个很有意思的报错:stack around the variable was corrupted
今天做一个很简单的oj来温习下c 语言 题目如下 输入 3位正整数 输出 逆置后的正整数 代码如下: #include"stdio.h"int main(){ float h,su ...
- 初探Java8中的HashMap(转)
HashMap是我们最常用的集合之一,同时Java8也提升了HashMap的性能.本着学习的原则,在这探讨一下HashMap. 原理 简单讲解下HashMap的原理:HashMap基于Hash算法,我 ...
- 从壹开始微服务 [ DDD ] 之十二 ║ 核心篇【下】:事件驱动EDA 详解
缘起 哈喽大家好,又是周二了,时间很快,我的第二个系列DDD领域驱动设计讲解已经接近尾声了,除了今天的时间驱动EDA(也有可能是两篇),然后就是下一篇的事件回溯,就剩下最后的权限验证了,然后就完结了, ...
- java8的新特性以及用法简介
1. 介绍 2 接口的默认方法 2 lambda表达式 2.1 函数式接口 2.2 方法与构造函数引用 2.3 访问局部变量 2.4 访问对象字段与静态变量 3. 内建函数式接口 3.1 Predic ...
- Java8新特性--流(Stream)
1.简介 Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性.在本文中我们一起来学习引入的一个新特性- ...
随机推荐
- 用 程序 解决 windows防火墙 的 弹窗 问题
今天用户反馈了一个问题,运行程序弹了个框 这个只有程序第一次运行会出来,之后就不会了. 当然改个程序名字,又会弹出来. 强烈怀疑是写到了注册表,果然被我找到了. “HKEY_LOCAL_MACHINE ...
- python中如何调用函数交换两个变量的值
python中如何调用函数交换两个变量的值 所有代码来在python3.7.1版本实现 以下实例通过用户输入两个变量,并相互交换: 方法一: def swap(a,b): # 创建临时变量,并交换 ...
- 使用 .NET CORE 创建 项目模板,模板项目,Template
场景:日常工作中,你可能会碰到需要新建一个全新的解决方案的情况(如公司新起了一个新项目,需要有全新配套的后台程序),如果公司内部基础框架较多.解决方案需要DDD模式等,那么从新起项目到各种依赖引用到能 ...
- jenkins无法连接到git原因
1.账号密码错误 2.公钥私钥不对应(git上为公钥,jenkins为私钥,私钥比公钥长) 3.公钥私钥文件没有复制到jenkins目录下的.ssh文件中
- npm install 安装很慢
npm install 安装很慢 设置国内镜像 npm config set registry https://registry.npm.taobao.org npm install
- spring-boot-plus快速快发脚手架简介
Everyone can develop projects independently, quickly and efficiently! Introduction spring-boot-plus是 ...
- Python之配置文件处理
在平时的工程中,我们在构建工程时,常常需要用到配置文件,用来配置项目的一些信息,比如数据库,请求网址,文件夹,线程.进程数等信息,这样就可以方便我们通过修改配置文件中的参数来很好地完成整个项目的功 ...
- GitExtensions使用教程
GitExtensions工具使用教程 第一步:安装 1.双击:GitExtensions24703SetupComplete.msi <ignore_js_op> image001.pn ...
- SpringBoot第二十四篇:应用监控之Admin
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 前一章(S ...
- JavaWeb实现增删查改(图书信息管理)——之查询
关于此次CRUD所需要的jar包,本人把文件放在了百度网盘,需要的自行去下载: 链接:https://pan.baidu.com/s/1Pqe88u6aPaeVjjOq1YFQ-w 提取码:pim ...