上两天阿海升级了一下JDK环境,IDE版本更新成了Eclipse Neon。

不得不说,这个版本的Eclipse确实很不错,用起来页比较舒服多了。尤其是这个Eclipse的暗黑主题“Drack”改进了不少,这也是我一直用的主题。且看我先秀一下图: 

 
这个主题中,改进最大的就是JSP编辑器,各种高亮很完全哦!js块中的语法高亮也很带感,然而美中不足的事,仍然没有JS的语法提示。各种图片我就不再秀了,这篇文章主要介绍JDK8的一些新的特性。

哦对了,假如喜欢这个版本的Eclipse的话,下面我给出了下载直连,想体验又不想翻墙的朋友们可以在下面的链接中下载(这个版本是64位的,需配合64位JDK使用。)

Eclipse: 
(被你们搞怕了,之前这个链接使阿里云OSS的直链,结果一晚上出去了一百多个G,欠费了,现在换成云盘,大数字的云盘速度也挺快的:https://yunpan.cn/ckbBr9dVeUDRt 访问密码 1daf)

JDK8: 
(被你们搞怕了,之前这个链接使阿里云OSS的直链,结果一晚上出去了一百多个G,欠费了,现在换成云盘,大数字的云盘速度也挺快的:https://yunpan.cn/ckbBEALLNGEfU 访问密码 0165)

之前如果有转载的朋友们请更新一下这个下载地址,求放过!

一,接口的默认方法

在JDK8中,允许给接口本身添加一个默认的实现。用“default”进行修饰。下面我创建一个MyCompute接口,并给他的sum方法一个默认的实现。

package com.aiyi.jdk.testinterface;/*** 我的Compute类* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:07:42*/
public interface MyCompute {/*** 定义加法运算并给他默认实现方法* @param i1 加数* @param i2 加数* @return 和*/default int sum(int i1, int i2){return i1 + i2;}/*** 定义减法运算接口* @param i1 减数* @param i2 被减数* @return 差*/int subtraction(int i1, int i2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

那么我来测试一下这个MyCompute,因为我已经给了他sum的默认实现,所以我只需要再实现 subtraction() 方法就行了:

public static void main(String[] args) {MyCompute c = new MyCompute() {@Overridepublic int subtraction(int i1, int i2) {// TODO Auto-generated method stubreturn i1 - i2;}};//Test sum function, result = 2int result = c.sum(1, 1);//Test subtraction function, result2 = 0int result2 = c.subtraction(1, -1);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

特性二,静态方法与构造函数的引用

这一点儿类似在C++中的《函数指针》的概念。我们可以这么理解(至少我是这么认为的),在Java中,方法和构造方法都看作是对象的一种,那么你要引用它(不是调用),则可以用::来引用。用来存储这个引用的类型用@FunctionlaInterface注解来标识。

方法引用对象的创建 
我继续以上面的例子进行解释,加入我要引用 MyCompute 中的 sun(int, int); 这个方法,可以就如下代码 
创建一个存储方法的对象:

package com.aiyi.jdk.testinterface;/*** 方法引用类* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:32:23*/
public class MyFunction {/*** 指向某个Function的方法指针* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:31:07* @param <F> 传值类型* @param <T> 结果类型*/@FunctionalInterfaceinterface Fun<F, T> {T run(F from);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

方法引用对象的使用

接下来我用这个Fun来引用一个方法。并执行他。(“Main::myMethod”表示 Main 类中的 myMethod() 方法) 
输出结果是”This is arg”

public static void main(String[] args) {Fun<String, String> fun = Main::myMethod;String result = fun.run("This is arg");System.out.println(result);}/*** 指向某个Function的方法指针* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:31:07* @param <F> 传值类型* @param <T> 结果类型*/@FunctionalInterfaceinterface Fun<F, T> {T run(F from);}public static String myMethod(String arg){return arg;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

构造函数引用对象的创建及使用

大同小异,就不多说了,输出结果“Creating”

public Main(String arg){System.out.println(arg);}@FunctionalInterfaceinterface mainFactory<M extends Main>{M run(String arg);}public static void main(String[] args) {mainFactory<Main> mainFun = Main::new;mainFun.run("Creating");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

特性三,玩死你不偿命的Lambda表达式

在JDK8中,引入了Lambda(读:了母的)表达式的概念,不得不说这Lambda实在是太强大了,强大了不止一点儿半点儿。看我一点儿一点儿慢慢的介绍它~

入门

(破天荒地用了一段儿英文注释,因为我在锻炼英文)

我来用一个简单的例子来讲解lambda有多么逆天。在JDK7中如果要对一个list进行排序的话,或许你是这样做的:

/*** This is the sorting of ‘JDK7’*/public static void testSort1(){List<String> list = Arrays.asList("asd","dweas","aw","trs");//Create a comparatorComparator<String> mySort = new Comparator<String>() {@Overridepublic int compare(String srt1, String str2) {// TODO Auto-generated method stubreturn srt1.compareTo(str2);}};//Sorting...Collections.sort(list, mySort);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

假如用lambda来完成上面这个排序的话,你可以一行代码搞定:

/*** This is the sorting of ‘JDK8' s lambda’(了母的)*/public static void testSort2(){List<String> list = Arrays.asList("asd","dweas","aw","trs");//Sorting...Collections.sort(list, (str1, str2) -> str1.compareTo(str2));}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

没错,就是这么嗨!仔细看“->”后面是一个Integer值得表达式,假如我的运算比较复杂的话,那么我还可以把他变成一个代码块:

/*** This is the sorting of ‘JDK8' s lambda’(了母的)*/public static void testSort2(){List<String> list = Arrays.asList("asd","dweas","aw","trs");//Sorting...Collections.sort(list, (str1, str2) -> {return str1.compareTo(str2);});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如果你以为lambda表达式就这么点儿含量的话,说出去会被人笑话的,上面只是举一个简单易懂的例子,这个例子运用的只是lambda表达式中的冰山一角!

Lambda表达式在Java中的定义:

每一个lambda表达式都对应一个类型,通常是接口类型。每一个Lambda表达式,都会匹配一个对应“函数式接口”的东西。

“函数式接口”是指仅仅只包含一个抽象方法的接口,即标注@FunctionalInterface的接口类。在上面刚刚就介绍了“函数式接口”了,请参阅《特性二》的说明

并且,你还可以给你的函数式接口添加默认方法。

我们重新创建一个MyFunction这个类

/*** 方法类* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:32:23*/
public class MyFunction {public static int sum(int i1, int i2){return i1 + i2;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

回到Main类中,我用Lambda表达式调用一下他,输出结果:2,即1+1的和

public static void main(String[] args) {Fun<Integer, Integer> fun = (i1, i2) -> MyFunction.sum(i1, i2);System.out.println(fun.run(1, 1));}/*** 指向某个Function的方法指针* @author 郭胜凯* @emai 719348277@qq.com* @time 2016年7月4日 下午1:31:07* @param <T> 参数1类型* @param <U> 参数2类型*/@FunctionalInterfaceinterface Fun<T, U> {int run(T arg1, U arg2);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

深入理解lambda

为了深入理解lambda,继续用之前的list排序案例来说,这次我们手动建立一个支持lambda的排序工具类。 
1、new一个抽象的比较器

package com.aiyi.jdk.testilambda;public interface MyComparator {int sort(String str1, String str2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、new一个排序工具类

package com.aiyi.jdk.testilambda;import java.util.List;public class MySortUtil {public static <T> void sortList (List<T> list, MyComparator<T> comparator){for (int i = 0; i < list.size(); i++) {for (int j = i + 1; j < list.size(); j++) {T temp = list.get(i);if (comparator.sort(list.get(i), list.get(j)) > 0) {list.set(i, list.get(j));list.set(j, temp);}}}}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3、使用lambda调用这个排序工具类进行排序

public static void testSort3(){List<String> list = Arrays.asList("asd","dweas","aw","trs");//Sorting...MySortUtil.sortList(list, (str1, str2) -> {return str1.compareTo(str2);});}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

搞定,是不是呢上面那个入门代码超级像?

lambda的作用域

lambda的作用域和内部类的作用于差不多,访问局部变量必须由final进行修饰。即不可更改。访问成员变量或者静态字段的话,则不需要final修饰,并且可以对其进行修改。 
JDK8中lambda支持的其他接口

Predicate 
predicate接收一个变量,并返回一个boolean值,predicate接口是一个简单的比进行较运算操作的接口,但一般不使用。例如:

Predicate<String> p = (str) -> str.equls("321aiyi.com");
sysout(p.test("321aiyi.com"));            //true
sysout(p.test("321aiyi.com").negate())    //false
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Function 
这个接口其实就是一个单纯的最简单的实现了@FunctionalInterface的接口类,一般对一个方法进行引用时,可以直接使用该接口。

Function<String, Integer> fun = String::valueOf;
String str = fun.apply(1);
  • 1
  • 2
  • 1
  • 2

Supplier 
这个就更简单了,他就相当于类的Factory,用它获取任意一个带有空参构造的类。

Supplier<StringBuffer> s = StringBuffer::new;
StringBuffer sb = s.get();
  • 1
  • 2
  • 1
  • 2

Consumer 
给定一个参数,并对其进行操作

Consumer<String> c = (str) -> System.out.pringln(str + "~~~");
c.accept("woca");        //"woca~~~"
  • 1
  • 2
  • 1
  • 2

另外,还有好多之前的接口也做了对lambda的支持,比如之前所说的Comparator接口等等,这里就不一一诉说了,喜欢钻研的朋友们可以拔源码或者阅读相关文档慢慢看。

特性四、反射的加强

JDK8加强了反射,它允许你直接通过反射获取参数的名字

很长一段时间里,Java程序员一直在发明不同的方式使得方法参数的名字能保留在Java字节码中,并且能够在运行时获取它们(比如,Paranamer类库)。最终,在Java 8中把这个强烈要求的功能添加到语言层面(通过反射API与Parameter.getName()方法)与字节码文件(通过新版的javac的–parameters选项)中。

package com.javacodegeeks.java8.parameter.names;import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class ParameterNames {public static void main(String[] args) throws Exception {Method method = ParameterNames.class.getMethod( "main", String[].class );for( final Parameter parameter: method.getParameters() ) {System.out.println( "Parameter: " + parameter.getName() );}}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果不使用–parameters参数来编译这个类,然后运行这个类,会得到下面的输出:

Parameter: arg0

如果使用–parameters参数来编译这个类,程序的结构会有所不同(参数的真实名字将会显示出来):

Parameter: args

对于有经验的Maven用户,通过maven-compiler-plugin的配置可以将-parameters参数添加到编译器中去。

针对java 8最新发布的Eclipse Kepler SR2提供了非常实用的配置选项,可以通过下图的配置方式来控制编译器行为,在这里,阿海在前面提到的Eclipse-Neon(目前最新的版本)版本同样具有这样的配置项,以下是开启该项的配置图: 

设置步骤:Window->Preferences->Java->Compiler 
此外,Parameter类有一个很方便的方法isNamePresent()来验证是否可以获取参数的名字。

下面的是我从网络上copy的,需要记得东西太多,copy下来慢慢消化。。。

Java 类库的新特性(copy)

Java 8 通过增加大量新类,扩展已有类的功能的方式来改善对并发编程、函数式编程、日期/时间相关操作以及其他更多方面的支持。

4.1 Optional

到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。

Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。更多详情请参考官方文档。

我们下面用两个小例子来演示如何使用Optional类:一个允许为空值,一个不允许为空值。

Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如果Optional类的实例为非空值的话,isPresent()返回true,否从返回false。 
为了防止Optional为空值,orElseGet()方法通过回调函数来产生一个默认值。map()函数对当前Optional的值进行转化,然后返回一个新的Optional实例。orElse()方法和orElseGet()方法类似,但是orElse接受一个默认值而不是一个回调函数。

下面是这个程序的输出:

Full Name is set? false Full 
Name: [none] 
Hey Stranger!

让我们来看看另一个例子:

Optional< String > firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

下面是程序输出

First Name is set? true 
First Name: Tom 
Hey Tom!

更多详情请参考官方文档(http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html)

Stream

最新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

Stream API极大简化了集合框架的处理(但它的处理的范围不仅仅限于集合框架的处理,这点后面我们会看到)。让我们以一个简单的Task类为例进行介绍:

public class Streams  {private enum Status {OPEN, CLOSED};private static final class Task {private final Status status;private final Integer points;Task( final Status status, final Integer points ) {this.status = status;this.points = points;}public Integer getPoints() {return points;}public Status getStatus() {return status;}@Overridepublic String toString() {return String.format( "[%s, %d]", status, points );}}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Task类有一个分数的概念(或者说是伪复杂度),其次是还有一个值可以为OPEN或CLOSED的状态.让我们引入一个Task的小集合作为演示例子:

final Collection< Task > tasks = Arrays.asList(new Task( Status.OPEN, 5 ),new Task( Status.OPEN, 13 ),new Task( Status.CLOSED, 8 )
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们下面要讨论的第一个问题是所有状态为OPEN的任务一共有多少分数?在Java 8以前,一般的解决方式用foreach循环,但是在Java 8里面我们可以使用stream:一串支持连续、并行聚集操作的元素。

// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks.stream().filter( task -> task.getStatus() == Status.OPEN ).mapToInt( Task::getPoints ).sum();System.out.println( "Total points: " + totalPointsOfOpenTasks );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

程序在控制台上的输出如下:

Total points: 18

这里有几个注意事项。第一,task集合被转换化为其相应的stream表示。然后,filter操作过滤掉状态为CLOSED的task。下一步,mapToInt操作通过Task::getPoints这种方式调用每个task实例的getPoints方法把Task的stream转化为Integer的stream。最后,用sum函数把所有的分数加起来,得到最终的结果。

在继续讲解下面的例子之前,关于stream有一些需要注意的地方(详情在这里).stream操作被分成了中间操作与最终操作这两种。

中间操作返回一个新的stream对象。中间操作总是采用惰性求值方式,运行一个像filter这样的中间操作实际上没有进行任何过滤,相反它在遍历元素时会产生了一个新的stream对象,这个新的stream对象包含原始stream 
中符合给定谓词的所有元素。

像forEach、sum这样的最终操作可能直接遍历stream,产生一个结果或副作用。当最终操作执行结束之后,stream管道被认为已经被消耗了,没有可能再被使用了。在大多数情况下,最终操作都是采用及早求值方式,及早完成底层数据源的遍历。

stream另一个有价值的地方是能够原生支持并行处理。让我们来看看这个算task分数和的例子。

// Calculate total points of all tasks
final double totalPoints = tasks.stream().parallel().map( task -> task.getPoints() ) // or map( Task::getPoints ) .reduce( 0, Integer::sum );System.out.println( "Total points (all tasks): " + totalPoints );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个例子和第一个例子很相似,但这个例子的不同之处在于这个程序是并行运行的,其次使用reduce方法来算最终的结果。 
下面是这个例子在控制台的输出:

Total points (all tasks): 26.0

经常会有这个一个需求:我们需要按照某种准则来对集合中的元素进行分组。Stream也可以处理这样的需求,下面是一个例子:

// Group tasks by their status
final Map< Status, List< Task > > map = tasks.stream().collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

这个例子的控制台输出如下:

{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}

让我们来计算整个集合中每个task分数(或权重)的平均值来结束task的例子。

// Calculate the weight of each tasks (as percent of total points)
final Collection< String > result = tasks.stream()                                        // Stream< String >.mapToInt( Task::getPoints )                     // IntStream.asLongStream()                                  // LongStream.mapToDouble( points -> points / totalPoints )   // DoubleStream.boxed()                                         // Stream< Double >.mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream.mapToObj( percentage -> percentage + "%" )      // Stream< String> .collect( Collectors.toList() );                 // List< String > System.out.println( result );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果

[19%, 50%, 30%]

最后,就像前面提到的,Stream API不仅仅处理Java集合框架。像从文本文件中逐行读取数据这样典型的I/O操作也很适合用Stream API来处理。下面用一个例子来应证这一点。

final Path path = new File( filename ).toPath();
try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

对一个stream对象调用onClose方法会返回一个在原有功能基础上新增了关闭功能的stream对象,当对stream对象调用close()方法时,与关闭相关的处理器就会执行。

Stream API、Lambda表达式与方法引用在接口默认方法与静态方法的配合下是Java 8对现代软件开发范式的回应。更多详情请参考官方文档(http://docs.oracle.com/javase/tutorial/collections/streams/index.html)。

Date/Time API (JSR 310)

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的影响,并且吸取了其精髓。新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。在设计新版API时,十分注重与旧版API的兼容性:不允许有任何的改变(从java.util.Calendar中得到的深刻教训)。如果需要修改,会返回这个类的一个新实例。

让我们用例子来看一下新版API主要类的使用方法。第一个是Clock类,它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。Clock可以替换System.currentTimeMillis()与TimeZone.getDefault()。

// Get the system clock as UTC offset
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

下面是控制台的输出

2014-04-12T15:19:29.282Z 
1397315969360

我们需要关注的其他类是LocaleDate与LocalTime。LocaleDate只持有ISO-8601格式且无时区信息的日期部分。相应的,LocaleTime只持有ISO-8601格式且无时区信息的时间部分。LocaleDate与LocalTime都可以从Clock中得到。

// Get the local date and local time
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );System.out.println( date );
System.out.println( dateFromClock );// Get the local date and local time
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );System.out.println( time );
System.out.println( timeFromClock );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

程序运行结果:

2014-04-12 
2014-04-12 
11:25:54.568 
15:25:54.568

LocaleDateTime把LocaleDate与LocaleTime的功能合并起来,它持有的是ISO-8601格式无时区信息的日期与时间。下面是一个快速入门的例子。

// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );System.out.println( datetime );
System.out.println( datetimeFromClock );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

控制台的输出

2014-04-12T11:37:52.309 
2014-04-12T15:37:52.309

如果你需要特定时区的日期/时间,那么ZonedDateTime是你的选择。它持有ISO-8601格式具具有时区信息的日期与时间。下面是一些不同时区的例子:

// Get the zoned date/time
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

下面是程序在控制台的输出

2014-04-12T11:47:01.017-04:00[America/New_York] 
2014-04-12T15:47:01.017Z 
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]

最后,让我们看一下Duration类:在秒与纳秒级别上的一段时间。Duration使计算两个日期间的不同变的十分简单。下面让我们看一个这方面的例子。

// Get duration between two dates
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面的例子计算了两个日期2014年4月16号与2014年4月16号之间的过程。下面是程序在控制台上的输出:

Duration in days: 365 
Duration in hours: 8783

对Java 8在日期/时间API的改进整体印象是非常非常好的。一部分原因是因为它建立在“久战杀场”的Joda-Time基础上,另一方面是因为用来大量的时间来设计它,并且这次程序员的声音得到了认可。更多详情请参考官方文档(http://docs.oracle.com/javase/tutorial/datetime/index.html)。

JavaScript引擎Nashorn

Nashorn,一个新的JavaScript引擎随着Java 8一起公诸于世,它允许在JVM上开发运行某些javascript应用。Nashorn就是javax.script.ScriptEngine的另一种实现,并且它们俩遵循相同的规则,允许Java与JavaScript相互调用。下面看一个例子:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );
System.out.println(engine.getClass().getName());
//Run JS
System.out.println("Result:" + engine.eval("function f() { return 1; }; f() + 1;"));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

控制台的输出:

jdk.nashorn.api.scripting.NashornScriptEngineResult: 2

Base64 
在Java 8中,Base64编码已经成为Java类库的标准。它的使用十分简单,下面让我们看一个例子:

package com.javacodegeeks.java8.base64;import java.nio.charset.StandardCharsets;
import java.util.Base64;public class Base64s {public static void main(String[] args) {final String text = "Base64 finally in Java 8!";final String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );System.out.println( encoded );final String decoded = new String( Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );System.out.println( decoded );}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

程序在控制台上输出了编码后的字符与解码后的字符:

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ== 
Base64 finally in Java 8!

Base64类同时还提供了对URL、MIME友好的编码器与解码器 
(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDecoder())。

并行(parallel)数组 
Java 8增加了大量的新方法来对数组进行并行处理。可以说,最重要的是parallelSort()方法,因为它可以在多核机器上极大提高数组排序的速度。下面的例子展示了新方法(parallelXxx)的使用。

package com.javacodegeeks.java8.parallel.arrays;import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;public class ParallelArrays {public static void main( String[] args ) {long[] arrayOfLong = new long [ 20000 ];        Arrays.parallelSetAll( arrayOfLong, index -> ThreadLocalRandom.current().nextInt( 1000000 ) );Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();Arrays.parallelSort( arrayOfLong );     Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

上面的代码片段使用了parallelSetAll()方法来对一个有20000个元素的数组进行随机赋值。然后,调用parallelSort方法。这个程序首先打印出前10个元素的值,之后对整个数组排序。这个程序在控制台上的输出如下(请注意数组元素是随机生产的):

Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 
Sorted: 39 220 263 268 325 607 655 678 723 793

并发(Concurrency) 
在新增Stream机制与lambda的基础之上,在java.util.concurrent.ConcurrentHashMap中加入了一些新方法来支持聚集操作。同时也在java.util.concurrent.ForkJoinPool类中加入了一些新方法来支持共有资源池(common pool)(请查看我们关于Java 并发的免费课程)。

新增的java.util.concurrent.locks.StampedLock类提供一直基于容量的锁,这种锁有三个模型来控制读写操作(它被认为是不太有名的java.util.concurrent.locks.ReadWriteLock类的替代者)。

在java.util.concurrent.atomic包中还增加了下面这些类:

  1. DoubleAccumulator
  2. DoubleAdder
  3. LongAccumulator
  4. LongAdder

新的Java工具

Java 8也带来了一些新的命令行工具。在这节里我们将会介绍它们中最有趣的部分。

Nashorn引擎: jjs 
jjs是个基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。例如,我们创建一个具有如下内容的func.js文件:

function f() { return 1;
}; print( f() + 1 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我们可以把这个文件作为参数传递给jjs使得这个文件可以在命令行中执行:

jjs func.js
  • 1
  • 1

得到程序运行结果:

2

类依赖分析器jdeps

jdeps是一个很有用的命令行工具。它可以显示Java类的包级别或类级别的依赖。它接受一个.class文件,一个目录,或者一个jar文件作为输入。jdeps默认把结果输出到系统输出(控制台)上。

下面我们查看现阶段较流行的spring框架类库的依赖报告,为了简化这个例子,我们只分析一个jar文件:org.springframework.core-3.0.5.RELEASE.jar

org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jarorg.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)-> java.io                                            -> java.lang                                          -> java.lang.annotation                               -> java.lang.ref                                      -> java.lang.reflect                                  -> java.util                                          -> java.util.concurrent                               -> org.apache.commons.logging                         not found-> org.springframework.asm                            not found-> org.springframework.asm.commons                    not foundorg.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)-> java.lang                                          -> java.lang.annotation                               -> java.lang.reflect                                  -> java.util
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Java虚拟机(JVM)的新特性

PermGen空间被移除了,取而代之的是Metaspace(JEP 122)。JVM选项-XX:PermSize与-XX:MaxPermSize分别被-XX:MetaSpaceSize与-XX:MaxMetaspaceSize所代替。

原文地址:https://blog.csdn.net/guoshengkai373/article/details/52368882

浅谈JDK8相对于JDK7的一些新特性相关推荐

  1. 浅谈同步整流的使用场景及器件特性

    大家好,我是电源漫谈 由于MOSFET可以正向导通电流的同时,还可以反向导通电流,因此,当使用二极管的时候,可以用一个MOSFET来代替它,本文就简要针对同步整流这一话题做一个简单讨论. 如何实现同步 ...

  2. 浅谈Redis的基本原理和数据类型结构的特性和应用开发场景

    一.Redis介绍 1,redis介绍(Redis安装在磁盘:Redis数据存储在内存) redis是一种基于键值对(key-value)数据库,其中value可以为string.hash.list. ...

  3. 浅谈angular的作用

    一.简单认识angular 1 AngularJS是什么? AngularJs(简称ng)是一个用于设计动态web应用的结构框架.首先,它是一个框架,不是类库,是像EXT一样提供一整套方案用于设计we ...

  4. 浅谈华为如何实现区块链的安全隐私保护

    摘要:区块链节点的租户隔离机制.安全合规性的国密算法支持机制以及范围可验证的同态加密机制下,华为区块链服务的增强安全特性浅谈. 1. 华为区块链服务安全特性介绍 本文介绍华为云区块链服务BCS(Blo ...

  5. jdk8新特性 lambda表达式详解

    本文主要讲到的内容有: 一- 前言 二- 背景 三- lambda表达式的语法 四- Lambda程序例子 4-1 Runnable Lambda 4-2 Comparator Lambda 4-3 ...

  6. 【JDK7】新特性(1) 概述

    2019独角兽企业重金招聘Python工程师标准>>> 准备 JDK7下载 http://download.java.net/jdk7/ API文档 http://download. ...

  7. 沈家桢:「我相、人相、众生相、寿者相。」浅谈

    我收到好几位朋友的信,认为「我相.人相.众生相.寿者相」这四相是<金刚经>中极重要的名词,可是我却没有详加解释,轻轻带过.希望我有机会再讲的时候,能先以此为题,加以申述.我很感激这几位朋友 ...

  8. 学校计算机机房好处,浅谈学校计算机机房维护

    浅谈学校计算机机房维护    现在的学校机房都配置了数量较多的计算机,而且机房的使用非常频繁.对于怎样维护好计算机,特别是计算机软件系统,对广大计算机教师来说是一个很重要且非常现实的问题.下面就本人在 ...

  9. 浅谈几种区块链网络攻击以及防御方案之其它网络攻击

    旧博文,搬到 csdn 原文:http://rebootcat.com/2020/04/16/network_attack_of_blockchain_other_attack/ 写在前面的话 自比特 ...

最新文章

  1. Jmeter脚本 GUI和非GUI启动方式
  2. 【caffe】create_cifar10.sh在windows下解决方案
  3. nopcommerce笔记3 还可以控制什么
  4. Innodb 的事物隔离级别实现原理(一)
  5. 第三章CDMA的原理和应用(3)
  6. 解决Office 2007 “向程序发送命令时出现问题”
  7. C#向PPT文档插入图片以及导出图片
  8. cad看图软件哪个更好用(免费cad看图软件推荐)
  9. 阿里云服务器CentOS8安装Kafka
  10. 使用JSON-Schema验证数据,第1部分
  11. 《量化交易:如何建立自己的算法交易》简介及PDF电子书下载
  12. TensorFlow 1.9终于对树莓派张开了怀抱:加入官方支持
  13. SaaS:云计算创业创新趋势
  14. 【小白爬POJ2431】3.6 探险车加油问 Expedition
  15. ../Libraries/core_cm3.c(445): error: non-ASM statement in naked function is not supported
  16. VoxelNet点云检测详解
  17. jsp连接数据库实现用户登录功能
  18. 花城fm v2.8.0
  19. GB28181-2016标准
  20. 机器学习概念总结笔记(一)——机器学习算法分类、最小二乘回归、岭回归、LASSO回归

热门文章

  1. 精彩的人生早已开始,看你怎么看待你的人生了
  2. 【狮子数学】01关于函数的四性的分析+复合函数+奇偶运算性质
  3. bert中文短文本句向量生成、相似度计算(GPU版、windows、win10、linux、django和flask可用)
  4. 2022电大国家开放大学网上形考任务-内科护理学(本)非免费(非答案)
  5. 通过主题词词典构建进行文本多标签分类
  6. hexo+NexT博客优化第二弹
  7. 计算机网络 使用eNSP搭建基础网络
  8. 整日碎片化学习“凡不凡”,android编程基础班
  9. 数据库系列之TiDB备份恢复
  10. 小妞会装机 -- 一个装机软件的开发笔记 (二)