Java 重学系列之JDK新特性汇总(一文就够了)
Posted amcomputer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 重学系列之JDK新特性汇总(一文就够了)相关的知识,希望对你有一定的参考价值。
JDK新特性汇总,收集网上各种资源整理。
目录
背景
JDK每个版本的特性太多了,虽然经常用到是JDK 7 or 8。故想用这篇博客来记录每个版本新内容,来当一个速出手册,并且增加一些Demo。
JDK 2
JDK 3
JDK 4
JDK 5
JDK 6
JDK 7
JDK7的新特性速查速记:
- 二进制字面量
- 数字字面量可以出现下划线
- switch 语句可以用字符串
- 泛型简化(即泛型推断)
- 异常的多个catch合并
- try-with-resources 语句
- 使用ForkJoin,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行。
1. 二进制字面量
JDK7开始,终于可以用二进制来表示整数(byte,short,int和long)。
使用二进制字面量的好处是,可以使代码更容易被理解。
语法非常简单,只要在二进制数值前面加 0b或者0B
举例:
int x = ob110110;
2. 数字字面量可以出现下划线
为了增强对数值的阅读性,如我们经常把数据用逗号分隔一样。JDK7提供了_对数据分隔。
举例:
int x = 100_1000;
注意事项:
不能出现在进制标识和数值之间
不能出现在数值开头和结尾
不能出现在小数点旁边
int a = 0b100_100;
int b = 0b_100_100;
int c = 0b100_100_;
float d = 12.34_56f;
float e = 12._34_56f;
你好奇底层是如何实现的吗?
3. switch 语句可以用字符串
以前只能用基本数据类型,现在可以使用String
4. 泛型简化(即泛型推断)
泛型实例的创建可以通过类型推断来简化,可以去掉后面new部分的泛型类型,只用<>就可以了。
List<String> list = new ArrayList<>();
5. 异常的多个catch合并
在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常。如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度。
try
//xxx
catch (A_Exception | B_Exception e)
e.printStackTrace();
6. try-with-resources 语句
以前打开的文件需要显示关闭,现在不用了,自动关闭资源。
格式:
try(必须是java.lang.AutoCloseable的子类对象)…
好处:
资源自动释放,不需要close()了
把需要关闭资源的部分都定义在这里就ok了
private static void method()
// try-with-resources 语句
// try(必须是java.lang.AutoCloseable的子类对象)…
try
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int ch = 0;
while ((ch = fr.read()) != -1)
fw.write(ch);
fw.close();
fr.close();
catch (IOException e)
e.printStackTrace();
// 改进版的代码
try (
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");)
int ch = 0;
while ((ch = fr.read()) != -1)
fw.write(ch);
catch (IOException e)
// 不需要关闭了,类似于python里面的with,上下文管理器
e.printStackTrace();
7. 使用ForkJoin
如何使用Fork/Join对大数据进行并行求和:
public class Main
public static void main(String[] args) throws Exception
// 创建2000个随机数组成的数组:
long[] array = new long[2000];
long expectedSum = 0;
for (int i = 0; i < array.length; i++)
array[i] = random();
expectedSum += array[i];
System.out.println("Expected sum: " + expectedSum);
// fork/join:
ForkJoinTask<Long> task = new SumTask(array, 0, array.length);
long startTime = System.currentTimeMillis();
Long result = ForkJoinPool.commonPool().invoke(task);
long endTime = System.currentTimeMillis();
System.out.println("Fork/join sum: " + result + " in " + (endTime - startTime) + " ms.");
static Random random = new Random(0);
static long random()
return random.nextInt(10000);
class SumTask extends RecursiveTask<Long>
static final int THRESHOLD = 500;
long[] array;
int start;
int end;
SumTask(long[] array, int start, int end)
this.array = array;
this.start = start;
this.end = end;
@Override
protected Long compute()
if (end - start <= THRESHOLD)
// 如果任务足够小,直接计算:
long sum = 0;
for (int i = start; i < end; i++)
sum += this.array[i];
// 故意放慢计算速度:
try
Thread.sleep(1);
catch (InterruptedException e)
return sum;
// 任务太大,一分为二:
int middle = (end + start) / 2;
System.out.println(String.format("split %d~%d ==> %d~%d, %d~%d", start, end, start, middle, middle, end));
SumTask subtask1 = new SumTask(this.array, start, middle);
SumTask subtask2 = new SumTask(this.array, middle, end);
invokeAll(subtask1, subtask2);
Long subresult1 = subtask1.join();
Long subresult2 = subtask2.join();
Long result = subresult1 + subresult2;
System.out.println("result = " + subresult1 + " + " + subresult2 + " ==> " + result);
return result;
JDK 8
JDK8的新特性速查速记:
1.Lambda表达式
2.新的日期API
3.引入Optional
4.使用Base64
5.接口的默认方法和静态方法
6.新增方法引用格式
7.新增Stream类
8.注解相关的改变
9.支持并行(parallel)数组
10.对并发类(Concurrency)的扩展。
1.Lambda表达式
这个特性个人觉得第一重要。因为使用频率和看到频率都太高了。
Lambda表达式是Java8中非常重要的一个新特性,其基于函数式编程的思想,支持将代码作为方法参数进行使 用。可以把Lambda表达式理解为通过一种更加简洁的方式表示可传递的匿名函数。 它本身没有名称,而且不像方法那样属于某一个类,但是可以有参数列表、代码体、返回值。使用了Lambda表达 式之后就不需要再去编写匿名类了
Lambda基础格式:
(参数列表) ‐>
方法体
参数列表:即匿名方法的形参 -> :Lambda运算符 方法体:用于执行业务逻辑。可以是单一语句,也可以是语句块。如果是单一语句,可以省略花括号。当需要返回 值,如果方法体中只有一条语句,可以省略return,会自动根据结果进行返回。
public class Test
public static void main(String[] args)
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
list.add("zhaoliu");
//for循环遍历
for (String s : list)
System.out.println(s);
//lambda表达式遍历
list.forEach(s -> System.out.println(s));
//匿名内部类
Runnable runnable = new Runnable()
@Override
public void run()
System.out.println("I'm running");
;
//lambda表达式
Runnable runnable1 = () -> System.out.println("I'm running");
2.新的日期API
Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。在旧版的 Java 中,日期时间 API 存在诸多问题,比如:
1.非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
2.设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
3.时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
1.Local(本地) − 简化了日期时间的处理,没有时区的问题。
2.Zoned(时区) − 通过制定的时区处理日期时间
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
3.引入Optional
用于尽量避免空指针异常
Optional类实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional 类的引入很好的解决空指针异常。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。尽量避免在程序中直接调用Optional对象的get()和isPresent()方法,避免使用Optional类型声明实体类的属性。
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回
torElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
Optional类示例
1.创建Optional类
( 1)使用empty()方法创建一个空的Optional对象:
Optional<String> empty = Optional.empty();
(2)使用of()方法创建Optional对象:
String name = "hhh";
Optional<String> opt = Optional.of(name);
assertEquals("Optional[hhh]", opt.toString());
传递给of()的值不可以为空,否则会抛出空指针异常。例如,下面的程序会抛出空指针异常。
String name = null;
Optional<String> opt = Optional.of(name);
如果我们需要传递一些空值,那我们可以使用下面的示例所示。
String name = null;
Optional<String> opt = Optional.ofNullable(name);
使用ofNullable()方法,则当传递进去一个空值时,不会抛出异常,而只是返回一个空的Optional对象,如同我们用Optional.empty()方法一样。
2.isPresent
我们可以使用这个isPresent()方法检查一个Optional对象中是否有值,只有值非空才返回true。
Optional<String> opt = Optional.of("binghe");
assertTrue(opt.isPresent());
opt = Optional.ofNullable(null);
assertFalse(opt.isPresent());
在Java8之前,我们一般使用如下方式来检查空值。
if(name != null)
System.out.println(name.length);
在Java8中,我们就可以使用如下方式来检查空值了。
Optional<String> opt = Optional.of("binghe");
opt.ifPresent(name -> System.out.println(name.length()));
3.orElse和orElseGet
(1)orElse
orElse()方法用来返回Optional对象中的默认值,它被传入一个“默认参数‘。如果对象中存在一个值,则返回它,否则返回传入的“默认参数”。
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("hhh");
assertEquals("hhh", name);
(2)orElseGet
与orElse()方法类似,但是这个函数不接收一个“默认参数”,而是一个函数接口。
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(() -> "hhh");
assertEquals("hhh", name);
(3)二者有什么区别?
要想理解二者的区别,首先让我们创建一个无参且返回定值的方法。
public String getDefaultName()
System.out.println("Getting Default Name");
return "hhh";
接下来,进行两个测试看看两个方法到底有什么区别。
String text;
System.out.println("Using orElseGet:");
String defaultText = Optional.ofNullable(text).orElseGet(this::getDefaultName);
assertEquals("hhh", defaultText);
System.out.println("Using orElse:");
defaultText = Optional.ofNullable(text).orElse(getDefaultName());
assertEquals("hhh", defaultText);
在这里示例中,我们的Optional对象中包含的都是一个空值,让我们看看程序执行结果:
Using orElseGet:
Getting default name...
Using orElse:
Getting default name...
两个Optional对象中都不存在value,因此执行结果相同。
那么,当Optional对象中存在数据会发生什么呢?我们一起来验证下。
String name = "hhh";
System.out.println("Using orElseGet:");
String defaultName = Optional.ofNullable(name).orElseGet(this::getDefaultName);
assertEquals("hhh", defaultName);
System.out.println("Using orElse:");
defaultName = Optional.ofNullable(name).orElse(getDefaultName());
assertEquals("hhh", defaultName);
运行结果如下所示。
Using orElseGet:
Using orElse:
Getting default name...
可以看到,当使用orElseGet()方法时,getDefaultName()方法并不执行,因为Optional中含有值,而使用orElse时则照常执行。所以可以看到,当值存在时,orElse相比于orElseGet,多创建了一个对象。如果创建对象时,存在网络交互,那系统资源的开销就比较大了,这是需要我们注意的一个地方。
4.orElseThrow
orElseThrow()方法当遇到一个不存在的值的时候,并不返回一个默认值,而是抛出异常。
tring nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow( IllegalArgumentException::new);
5.get
get()方法表示是Optional对象中获取值。
Optional<String> opt = Optional.of("hhh");
String name = opt.get();
assertEquals("hhh", name);
使用get()方法也可以返回被包裹着的值。但是值必须存在。当值不存在时,会抛出一个NoSuchElementException异常。
Optional<String> opt = Optional.ofNullable(null);
String name = opt.get();
6.filter
接收一个函数式接口,当符合接口时,则返回一个Optional对象,否则返回一个空的Optional对象。
String name = "hhh";
Optional<String> nameOptional = Optional.of(name);
boolean isBinghe = nameOptional.filter(n -> "hhh".equals(name)).isPresent();
assertTrue(isBinghe);
boolean ishhh = nameOptional.filter(n -> "hhh".equ以上是关于Java 重学系列之JDK新特性汇总(一文就够了)的主要内容,如果未能解决你的问题,请参考以下文章