您的位置:首页 > 编程语言 > Java开发

jdk1.8新特性

2017-06-18 20:12 411 查看
package com.star.lamda;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
* Created by taojiang211638 on 2017/6/18.
*/
public class Person {

/**
* 使用lambda方式
*/
public void mutiThreadLambda(){
Thread thread =   new Thread(new Runnable(){
public void run(){
System.out.println("not use Lambda method");
}
});
thread.start();

Thread threadLam = new Thread(()->{
System.out.println("use Lambda method:");
});
threadLam.start();
}

/**
* 使用lambda边里数组
*/
public void foreachArray(){
List<String> list = Arrays.asList("aaa","bbb","ccc");
for (String str: list){
System.out.println(str);
}

list.forEach((str) ->System.out.println(str));
}

public static void main(String[] args) {
Person person = new Person();

person.mutiThreadLambda();

person.foreachArray();

printlnList();
printlnMap();
}

public static void printlnMap(){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> stream = numbers.stream();
stream.filter((x) -> {
return x % 2 == 0;
}).map((x) -> {
return x * x;
}).forEach(System.out::println);
}

public static void printlnList() {

List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

for(String name: languages)  {
if(name.length() > 3 && name.startsWith("H")) {
System.out.println(name + " ");
}
}
languages.forEach((name) -> {
if (name.length() > 3 && name.startsWith("H")) {
System.out.println(name);
}
});

languages.stream().filter(name -> name.length() > 3 && name.startsWith("H") ).map(name -> name+name).forEach((name) -> {
System.out.println(name);
});
}

public static void main2(String[] args){

}
}


默认方法

Java 8 还允许我们给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,这个特征又叫做扩展方法。在实现该接口时,该默认扩展方法在子类上可以直接使用,它的使用方式类似于抽象类中非抽象成员方法。但扩展方法不能够重载 Object 中的方法。例如:toString、equals、 hashCode 不能在接口中被重载。

例如,下面接口中定义了一个默认方法 count(),该方法可以在子类中直接使用。

1

2

3

4

5

6

7

8

9

10

11

12

13

public interface DefaultFunInterface {

//定义默认方法 count

default int count(){

return 1;

}

}

public class SubDefaultFunClass implements DefaultFunInterface {

public static void main(String[] args){

//实例化一个子类对象,改子类对象可以直接调用父接口中的默认方法 count

SubDefaultFunClass sub = new SubDefaultFunClass();

sub.count();

}

}

静态方法

在接口中,还允许定义静态的方法。接口中的静态方法可以直接用接口来调用。

例如,下面接口中定义了一个静态方法 find,该方法可以直接用 StaticFunInterface .find() 来调用。

1

2

3

4

5

6

7

8

9

10

11

public interface StaticFunInterface {

public static int find(){

return 1;

}

}

public class TestStaticFun {

public static void main(String[] args){

//接口中定义了静态方法 find 直接被调用

StaticFunInterface.fine();

}

}

集合之流式操作

Java 8 引入了流式操作(Stream),通过该操作可以实现对集合(Collection)的并行处理和函数式操作。根据操作返回的结果不同,流式操作分为中间操作和最终操作两种。最终操作返回一特定类型的结果,而中间操作返回流本身,这样就可以将多个操作依次串联起来。根据流的并发性,流又可以分为串行和并行两种。流式操作实现了集合的过滤、排序、映射等功能。

Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。

串行和并行的流

流有串行和并行两种,串行流上的操作是在一个线程中依次完成,而并行流则是在多个线程上同时执行。并行与串行的流可以相互切换:通过 stream.sequential() 返回串行的流,通过 stream.parallel() 返回并行的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。

下面是分别用串行和并行的方式对集合进行排序。

串行排序:

1

2

3

4

5

6

7

8

9

10

List list = new ArrayList();

for(int i=0;i<1000000;i++){

double d = Math.random()*1000;

list.add(d+”“);

}

long start = System.nanoTime();//获取系统开始排序的时间点

int count= (int) ((Stream) list.stream().sequential()).sorted().count();

long end = System.nanoTime();//获取系统结束排序的时间点

long ms = TimeUnit.NANOSECONDS.toMillis(end-start);//得到串行排序所用的时间

System.out.println(ms+”ms”);

并行排序:

1

2

3

4

5

6

7

8

9

10

11

List list = new ArrayList();

for(int i=0;i<1000000;i++){

double d = Math.random()*1000;

list.add(d+”“);

}

long start = System.nanoTime();//获取系统开始排序的时间点

int count = (int)((Stream) list.stream().parallel()).sorted().count();

long end = System.nanoTime();//获取系统结束排序的时间点

long ms = TimeUnit.NANOSECONDS.toMillis(end-start);//得到并行排序所用的时间

System.out.println(ms+”ms”);

串行输出为 1200ms,并行输出为 800ms。可见,并行排序的时间相比较串行排序时间要少不少。

中间操作

该操作会保持 stream 处于中间状态,允许做进一步的操作。它返回的还是的 Stream,允许更多的链式操作。常见的中间操作有:

filter():对元素进行过滤;

sorted():对元素排序;

map():元素的映射;

distinct():去除重复元素;

subStream():获取子 Stream 等。

例如,下面是对一个字符串集合进行过滤,返回以“s”开头的字符串集合,并将该集合依次打印出来:

1

2

3

list.stream()

.filter((s) -> s.startsWith(“s”))

.forEach(System.out::println);

这里的 filter(…) 就是一个中间操作,该中间操作可以链式地应用其他 Stream 操作。

终止操作

该操作必须是流的最后一个操作,一旦被调用,Stream 就到了一个终止状态,而且不能再使用了。常见的终止操作有:

forEach():对每个元素做处理;

toArray():把元素导出到数组;

findFirst():返回第一个匹配的元素;

anyMatch():是否有匹配的元素等。

例如,下面是对一个字符串集合进行过滤,返回以“s”开头的字符串集合,并将该集合依次打印出来:

1

2

3

list.stream() //获取列表的 stream 操作对象

.filter((s) -> s.startsWith(“s”))//对这个流做过滤操作

.forEach(System.out::println);

这里的 forEach(…) 就是一个终止操作,该操作之后不能再链式的添加其他操作了。

注解的更新

对于注解,Java 8 主要有两点改进:类型注解和重复注解。

Java 8 的类型注解扩展了注解使用的范围。在该版本之前,注解只能是在声明的地方使用。现在几乎可以为任何东西添加注解:局部变量、类与接口,就连方法的异常也能添加注解。新增的两个注释的程序元素类型 ElementType.TYPE_USE 和 ElementType.TYPE_PARAMETER 用来描述注解的新场合。ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中。而 ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中(例如声明语句、泛型和强制转换语句中的类型)。

对类型注解的支持,增强了通过静态分析工具发现错误的能力。原先只能在运行时发现的问题可以提前在编译的时候被排查出来。Java 8 本身虽然没有自带类型检测的框架,但可以通过使用 Checker Framework 这样的第三方工具,自动检查和确认软件的缺陷,提高生产效率。

例如,下面的代码可以通过编译,但是运行时会报 NullPointerException 的异常。

1

2

3

4

5

6

public class TestAnno {

public static void main(String[] args) {

Object obj = null;

obj.toString();

}

}

为了能在编译期间就自动检查出这类异常,可以通过类型注解结合 Checker Framework 提前排查出来:

1

2

3

4

5

6

7

import org.checkerframework.checker.nullness.qual.NonNull;

public class TestAnno {

public static void main(String[] args) {

@NonNull Object obj = null;

obj.toString();

}

}

编译时自动检测结果如下:

1

2

3

4

5

6

7

C:\workspace\TestJava8\src\TestAnno.java:4: Warning:

(assignment.type.incompatible) 2 null @UnknownInitialization@NonNullObject ( 152, 156 )

$$ incompatible types in assignment.

@NonNull Object obj = null;

^

found : null

required: @UnknownInitialization @NonNull Object

另外,在该版本之前使用注解的一个限制是相同的注解在同一位置只能声明一次,不能声明多次。Java 8 引入了重复注解机制,这样相同的注解可以在同一地方声明多次。重复注解机制本身必须用 @Repeatable 注解。

例如,下面就是用 @Repeatable 重复注解的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

@Retention(RetentionPolicy.RUNTIME) \该注解存在于类文件中并在运行时可以通过反射获取

@interface Annots {

Annot[] value();

}

@Retention(RetentionPolicy.RUNTIME) \该注解存在于类文件中并在运行时可以通过反射获取

@Repeatable(Annots.class)

@interface Annot {

String value();

}

@Annot(“a1”)@Annot(“a2”)

public class Test {

public static void main(String[] args) {

Annots annots1 = Test.class.getAnnotation(Annots.class);

System.out.println(annots1.value()[0]+”,”+annots1.value()[1]);

// 输出: @Annot(value=a1),@Annot(value=a2)

Annot[] annots2 = Test.class.getAnnotationsByType(Annot.class);

System.out.println(annots2[0]+”,”+annots2[1]);

// 输出: @Annot(value=a1),@Annot(value=a2)

}

}

注释 Annot 被 @Repeatable( Annots.class ) 注解。Annots 只是一个容器,它包含 Annot 数组, 编译器尽力向程序员隐藏它的存在。通过这样的方式,Test 类可以被 Annot 注解两次。重复注释的类型可以通过 getAnnotationsByType() 方法来返回。

安全性

现今,互联网环境中存在各种各种潜在的威胁,对于 Java 平台来说,安全显得特别重要。为了保证新版本具有更高的安全性,Java 8 在安全性上对许多方面进行了增强,也为此推迟了它的发布日期。下面例举其中几个关于安全性的更新:

支持更强的基于密码的加密算法。基于 AES 的加密算法,例如 PBEWithSHA256AndAES_128 和 PBEWithSHA512AndAES_256,已经被加入进来。

在客户端,TLS1.1 和 TLS1.2 被设为默认启动。并且可以通过新的系统属性包 jdk.tls.client.protocols 来对它进行配置。

Keystore 的增强,包含新的 Keystore 类型 java.security.DomainLoadStoreParameter 和为 Keytool 这个安全钥匙和证书的管理工具添加新的命令行选项-importpassword。同时,添加和更新了一些关于安全性的 API 来支持 KeyStore 的更新。

支持安全的随机数发生器。如果随机数来源于随机性不高的种子,那么那些用随机数来产生密钥或者散列敏感信息的系统就更易受攻击。SecureRandom 这个类的 getInstanceStrong 方法如今可以获取各个平台最强的随机数对象实例,通过这个实例生成像 RSA 私钥和公钥这样具有较高熵的随机数。

JSSE(Java(TM) Secure Socket Extension)服务器端开始支持 SSL/TLS 服务器名字识别 SNI(Server Name Indication)扩展。SNI 扩展目的是 SSL/TLS 协议可以通过 SNI 扩展来识别客户端试图通过握手协议连接的服务器名字。在 Java 7 中只在客户端默认启动 SNI 扩展。如今,在 JSSE 服务器端也开始支持 SNI 扩展了。

安全性比较差的加密方法被默认禁用。默认不支持 DES 相关的 Kerberos 5 加密方法。如果一定要使用这类弱加密方法需要在 krb5.conf 文件中添加 allow_weak_crypto=true。考虑到这类加密方法安全性极差,开发者应该尽量避免使用它。

IO/NIO 的改进

Java 8 对 IO/NIO 也做了一些改进。主要包括:改进了 java.nio.charset.Charset 的实现,使编码和解码的效率得以提升,也精简了 jre/lib/charsets.jar 包;优化了 String(byte[],*) 构造方法和 String.getBytes() 方法的性能;还增加了一些新的 IO/NIO 方法,使用这些方法可以从文件或者输入流中获取流(java.util.stream.Stream),通过对流的操作,可以简化文本行处理、目录遍历和文件查找。

新增的 API 如下:

BufferedReader.line(): 返回文本行的流 Stream

File.lines(Path, Charset):返回文本行的流 Stream

File.list(Path): 遍历当前目录下的文件和目录

File.walk(Path, int, FileVisitOption): 遍历某一个目录下的所有文件和指定深度的子目录

File.find(Path, int, BiPredicate, FileVisitOption… ): 查找相应的文件

下面就是用流式操作列出当前目录下的所有文件和目录:

1

2

Files.list(new File(“.”).toPath())

.forEach(System.out::println);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: