JAVA8 特性

一、Lambda表达式

百度百科定义:

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

Lambda 表达式表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。Lambda表达式有利于函数式编程,简化了开发了很多。 

lambda表达式的重要特征:

  • 可选类型声明 - 无需声明参数的类型。编译器可以从该参数的值推断。
  • 可选圆括号参数 - 无需在括号中声明参数。对于多个参数,括号是必需的。
  • 可选大括号 - 表达式主体没有必要使用大括号,如果主体中含有一个单独的语句。
  • 可选return关键字 - 编译器会自动返回值,如果主体有一个表达式返回的值。花括号是必需的,以表明表达式返回一个值。
 
public  class  Lambda表达式 {
     public  static  void  main(String[] args) {
         Lambda表达式 tester =  new  Lambda表达式();
         // 可以声明类型
         MathOperation addition = ( int  a,  int  b) -> a + b;
         // 可以不声明类型,编译器可以根据参数推断
         MathOperation subtraction = (a, b) -> a - b;
         // 单个参数入参可以不使用括号
         MathOneParam addOne = a -> a +  1 ;
         // return 可选,如果表达式只有一行的,大括号可选
         MathOperation multiplication = ( int  a,  int  b) -> {
             return  a * b;
         };
         // 无return 无大括号
         MathOperation division = ( int  a,  int  b) -> a / b;
         System.out.println( "10 + 5 = "  + addition.operation( 10 , 5 ));
         System.out.println( "10 - 5 = "  + subtraction.operation( 10 5 ));
         System.out.println( "10 x 5 = "  + tester.operate( 10 5 , multiplication));
         System.out.println( "10 / 5 = "  + tester.operate( 10 5 , division));
     }
 
     interface  MathOperation {
         int  operation( int  a,  int  b);
     }
     interface  MathOneParam {
         int  operation( int  a);
     }
}

运行结果:

总结:

  • lambda表达式主要用于定义内联执行的功能的接口,即只有一个单一的方法接口。Java8定义被广泛应用于lambda表达式很多函数形式的接口。以下是在java.util.Function包中定义的功能接口列表。
 


 

  • Lambda表达式消除匿名类的需求,并给出了一个非常简单但功能强大的函数式编程能力。函数式编程扫盲

变量的作用域

 


public  class  Lambda表达式 {
     private  static  String HELLO =  "hello!" ;
     public  static  void  main(String[] args) {
         Lambda表达式 tester =  new  Lambda表达式();
         //===========================变量的作用域=============================== 
         //String HELLO = "turuiHello";
         GreetingService greetService1 = message -> System.out.println(HELLO+ " "  + message);
         GreetingService greetService2 = (message) -> System.out.println(HELLO + " "  + message);
         
         //请说明下输出结果?
         greetService1.sayMessage( "Mahesh" );
         tester.testScope( "Haolong" , greetService1);
         greetService2.sayMessage( "Suresh" );
     }
 
     interface  GreetingService {
         void  sayMessage(String message);
     }  
     private  void  testScope(String message,GreetingService greetingService){
         HELLO =  "你好!" ;
         greetingService.sayMessage(message);
     }
}

运行结果1:

运行结果2:

总结:

在lambda表达式,可以指任何最终的变量或有效的最后一个变量(被分配一次)。

二、接口的默认方法和静态方法

java 8版之前,接口只有抽象方法,而在Java 8,为接口新增了两种类型的方法。

interface  InterfaceA{
     // 支持默认方法,关键字default
     default  void  print(){
         System.out.println( "default method A" );
     }
     // 支持静态方法
     static  void  staticMethod(){
         System.out.println( "static method" );
     }
}
 
interface  InterfaceB{
     default  void  print(){
         System.out.println( "default method B" );
     }
}
 
class  TestInterface  implements  InterfaceA,InterfaceB {
     //方案一:覆盖后重写方法
     public  void  print() {
         // TODO Auto-generated method stub
         System.out.println( "sub method" );
     }
     //方案二:指定某个接口的默认方案
     public  void  print() {
         // TODO Auto-generated method stub
         InterfaceA. super .print();
     }
}

结论:

  • 第一种是默认方法。此方法使用了default关键字修饰方法名。实际上接口不包含任何实现的方法,而在Java 8中,可以通过使用default关键字来添加默认的方法实现。
  • 这一点与类中的静态方法相似,可以在接口中使用static关键字定义静态方法。如果我们要调用接口定义的静态方法,只需使用接口名就可以访问这些静态方法。

 

三、JAVA 8 Stream

流代表从支持聚合操作源的序列的对象。以下是数据流的特点。

  • 元素序列 - 流提供了一组特定类型的以顺序方式元素。流获取/计算需求的元素。它不存储元素。
  • 源- 流使用集合,数组或I/O资源为输入源。
  • 聚合操作 - 数据流支持如filter, map, limit, reduced, find, match等聚合操作。
  • 管道传输 - 大多数流操作的返回流本身使他们的结果可以被管道传输。这些操作被称为中间操作以及它们的功能是利用输入,处理输入和输出返回到目标。collect()方法是终端操作,这是通常出现在管道传输操作结束标记流的结束。
  • 自动迭代 - 流操作内部做了反复对比,其中明确迭代需要集合提供源元素。

创建Stream

方法
用法
例子
备注

Collection子类获取Stream

Collection子类.stream()

List list = new ArrayList();

list.stream();

 
Stream接口的generator静态方法,生成一个无限长度的Stream Stream.generate()

Stream.generate(() -> Math.random());

Stream.generate(Math::random);

创建无穷stream
Stream接口的of静态方法  Stream.of() Stream<Integer> integerStream = Stream.of(1235);  


Stream常用操作

ForEach

ForEach:数据流提供了新的forEach方法遍历该流中的每个元素

List<String> strings = Arrays.asList( "abc" "" "bc" "efg" "abcd" , "" "jkl" );
//ForEach 数据流提供了新的forEach方法遍历该流中的每个元素。
strings.stream().forEach(string->System.out.println(string));

map

map:map 方法用于映射每个元素对应的结果

    //map 方法用于映射每个元素对应的结果。
     List<Integer> numbers = Arrays.asList( 3 2 2 3 7 3 5 );
     //get list of unique squares
     List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

filter

filter:filter方法用于消除基于标准元素

    //filter方法用于消除基于标准元素。 R表达式实际上是初始化了Predicate的test方法,返回boolean
     List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
     filtered.stream().forEach(System.out::println);

limit

limit:方法用于减少流的大小

//limit 方法用于减少流的大小。
List<Integer> listLimit = Arrays.asList( 1 3 2 4 5 );
listLimit.stream().limit( 2 ).forEach(System.out::println); 

sorted

sorted:用来流排序

 

//sorted方法用来流排序。
System.out.println( "---------asc sort----------" );
listLimit.stream().sorted().forEach(System.out::println);
System.out.println( "---------desc sort----------" );
listLimit.stream().sorted((a,b)->b-a).forEach(System.out::println);

collect

collect:收集器是用来处理组合在一个数据流的元素的结果。收集器可用于返回一个列表或一个字符串。

List<String> collectors = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
collectors.stream().forEach(System.out::println);
String collectorResut = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining( "," ));
System.out.println(collectorResut);

统计

summaryStatistics:使用Java8,统计收集器引入计算所有统计数据时,流处理可以做这些。

List<Integer> numbersStatistic = Arrays.asList( 3 2 2 3 7 3 5 );
IntSummaryStatistics stats = numbersStatistic.stream().mapToInt((x) -> x).summaryStatistics();    
System.out.println( "Highest number in List : "  + stats.getMax());
System.out.println( "Lowest  number in List : "  + stats.getMin());
System.out.println( "Sum of all numbers : "  + stats.getSum());
System.out.println( "Average of all  numbers : "  + stats.getAverage());

 

四、Optional类

Optional用于包含非空对象的容器对象。Optional对象,用于表示使用不存在null值。这个类有各种实用的方法,以方便代码来处理为可用或不可用,而不是检查null值。它是Java引入, 是类似于在 Guava 中的 Optional 。

import  java.util.Optional;
public  class  Optional对象 {
     public  static  void  main(String[] args){
         Optional<String> option1 = Optional.of( "test optional" );
         String nullStr =  null ;
         Optional<String> option2 = Optional.ofNullable(nullStr);
         
         System.out.println(option1.isPresent());
         System.out.println(option2.isPresent());
     }
}

五、日期时间API扩展

使用Java8,新的日期时间API引入覆盖旧的日期时间API的以下缺点。

  • 非线程安全 - java.util.Date不是线程安全的,因此开发者必须在使用日期处理并发性问题。新的日期时间API是不可变的,并且没有setter方法。
  • 设计不佳 - 默认的开始日期从1900年,开始每月从1天从0开始,所以没有统一。不直接使用方法操作日期。新的API提供了这样操作实用方法。
  • 困难的时区处理 - 开发人员必须编写大量的代码来处理时区的问题。新的API设计开发保持特定领域设计。

 

JAVA8引入了java.time包 - 下一个新的日期时间API。以下是一些在java.time程序包引入重要的类。【与joda-time用法相似】

  • 本地 - 简化日期时间API,没有时间处理区的复杂性。
  • 时区 - 专业的日期时间API来处理各种时区。

 

六、并行、并发

并行(parallel)数组

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

public  class  ParallelSort {
     public  static  void  main(String[] args){
         int  arr[] = { 1 4 2 8 5 };
         Arrays.parallelSort(arr);
         for ( int  i : arr){
             System.out.print(i +  " " );
         }
     }
}

并发(Concurrency)

在新增Stream机制与lambda的基础之上,在java.util.concurrent.ConcurrentHashMap中加入了一些新方法来支持聚集操作。同时也在java.util.concurrent.ForkJoinPool类中加入了一些新方法来支持共有资源池(common pool)。

java8中对ConcurrentHashMap的改进 :

改进一:取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。

改进二:将原先table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构。对于个数超过8(默认值)的列表,jdk1.8中采用了红黑树的结构改进性能。

七、JAVA 8内存划分

 

       JDK8中HotSpot JVM不再有PermGen,类的元数据信息(metadata)还在,只不过不再是存储在连续的堆空间上,而是移动到叫做“Metaspace”的本地内存(Native memory)中。

       元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:链接

  -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
  -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

  除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
  -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
  -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

使用元空间的几点原因:

  1、字符串存在永久代中,容易出现性能问题和内存溢出。

  2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。

  3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。

  4、Oracle 可能会将HotSpot 与 JRockit 合二为一。

科普(小道消息)链接

        JDK8 HotSpot JVM 使用本地内存来存储类元数据信息并称之为:元空间(Metaspace),这与Oracle JRockit 和IBM JVM’s很相似。由于类的元数据可以在本地内存(native memory)之外分配,所以其最大可利用空间是整个系统内存的可用空间。这样,你将不再会遇到OOM错误,溢出的内存会涌入到交换空间。这个新特性也不能神奇地消除类和类加载器导致的内存泄漏。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值