java8 新特性整理

本文详细介绍了Java8中的新特性,包括HashMap的优化,从JDK1.7的链表结构升级到JDK1.8的链表-红黑树结构,提高了查询和插入效率。另外,重点讲解了Lambda表达式的概念、语法和应用场景,以及四大核心函数式接口。此外,还提及了Optional类、接口的默认方法、新的日期和时间API、重复注解和类型注解等其他新特性。
摘要由CSDN通过智能技术生成

一、JDK8新特性

1、hashMap优化

1.1、Jdk1.7中:hashmap(数组(16)-链表)

 

​ 使用一个Entry数组存储数据,用key的hashcode取模来决定key会被分配到数组的位置,如果hashcode相同,或者hashcode取模后的结果相同(hash collison),那么这些key会被定位到Entry数组的同一个格子里,这些key会形成一个链表。如果在同一个格子里,会调用equals()方法,比较对象是否是同一个,若是同一个,则将值替换成最新的,若不是,将刚插入的对象放在最前面,其他依次后移,最终形成一个链表。

​ 在hashcode特别差的情况下,比如说所有的key的hashcode都相同,这个链表可能很长,那么put/get操作都可能需要遍历这个链表。HashMap分配的空间有限,需要一个加载因子如果你hashmap的空间有100,那么当你插入了75个元素的时候,hashmap就需要扩容了,不然的话会形成很长散列桶,对于查询和插入都会增加时间,因为他要一个一个的equals。但是你又不能让加载因子很小,0.01这样是不合适的,因为他会大大消耗你的 内存, 你一加入一个对象hashmap就扩容。这时就存在着一个平衡,jdk中默认是0.75,可以根据自己的实际情况进行调整。

1.2、Jdk1.8 中:hashMap(数组-链表-红黑树)

​ 使用一个Node数组来存储数据,但这个Node可能是链表结构,也可能是红黑树结构,如果插入的key的hashcode相同,那么这些key也会被定位到Node数组的同一个格子里。如果同一个格子的key不超过8个,使用链表结构存储。如果超过了8个,那么会调用treeifyBin()函数,将链表转换为红黑树。除添加之外其他效率都高。

注意:但是真正想要利用JDK1.8的好处,有一个限制:key的对象,必须正确的实现了Compare接口如果没有实现Compare接口,或者实现得不正确(比方说所有Compare方法都返回0)那JDK1.8的HashMap其实还是慢于JDK1.7的。

1.3、ConcurrentHashMap

在JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,如下图所示:

 

​ Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是上面的提到的锁分离技术,而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样。

​ JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本。

 

2、Lambda表达式

2.1、 Lambda表达式:

一个lambda可以由用逗号分隔的参数列表、–>符号与函数体三部分表示.引入特殊的操作符”->”

​ 左侧:lambda 表达式参数列表。

​ 右侧:lambda 表达式体,即要执行的功能。

语法一:无参数,无返回值,匿名内部类变量被final修饰

语法二:有一个参数,无返回值

Consumer consumer = (x)-> System.out.println(x);
consumer.accept("我真帅");

语法三:有两个以上参数,有返回值,lambda有多条语句。(如果只有一条语句,大括号和return都可以不写)

Comparator<Integer> com = (x,y)->{
    System.out.println(".....");
    return Integer.compare(x,y);
};
​

 

语法四:Lambda表达式的参数列表的数据类型可以不写,因为JVM的编译器可以通过上下文推断出。

Lambda表达式需要”函数式接口”的支持

函数是接口:接口中只有一个抽象方法的接口,称为函数式接口,可以使用注解@FunctionalInterface修饰,可以检查是否是函数式接口。

2.2、 Java8 内置的四大核心函数式接口

(1) Consumer<T>:消费型接口

​ void accept(T t);

(2) Supplier<T>: 供给型接口

​ T get();

(3) Function<T,R>:函数型接口

​ R apply(T t);

(4) Predicate<T> : 断言型接口

​ boolean test(T t);

 

2.3 、方法的引用:

​ 若Lambda体中的内容方法已经实现了,我们可以使用”方法引用”---Lambda的另一种表达形式。

主要有三种语法格式:

(1) 对象::实现方法名

Employee emp = new Employee(); 
Supplier<String> supplier = ()->emp.getName();
String name = supplier.get();
   ------>>>
​
 Supplier<String> sup = Emp::getName;
 String name = sup.get();
​

(2) 类::静态方法名

Comparator<Integer> com = (x,y)->Integer.compare(x,y); 
Comparator<Integer> com1 = Integer::compare;

 

(3) 类::实例方法名

BiPredicate<String,String> bp = (x,y)-> x.equals(y); // x:实例方法的调用者
​
BiPredicate<String,String> bp2 = String::equals;

 

注意:①Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型保持一致。

​ ②若 Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用CalssName::method。eg:类::实例方法名的实例

 

2.4、 构造器引用

2.4.1、 格式:ClassName::new

@Test
public void test7() {
    Supplier<Employee> sup = () -> new Employee();
    Employee employee = sup.get();
    /*构造器引用/,无参构造*/  
    Supplier<Employee> supm = Employee::new;
    System.out.println(supm.get()); ---get()无参
    //有参构造
    EmployeeInterFace<Integer,String,Integer,Double,Employee> supplier =(a,s,d,f)->new Employee(a,s,d,f);
    EmployeeInterFace<Integer,String,Integer,Double,Employee> supplier1=Employee::new;
    System.out.println(supplier1.grenter(102,"张三",23,4444.44));
}

 

//有参构造函数式接口
@FunctionalInterface
public interface EmployeeInterFace<T,R,E,F,G> {
    public G grenter(T t,R r,E e,F f);
}

 

注意:构造器参数列表要与接口参数列表保持一致。

2.4.2、Stream:是数据渠道,用于操作数据源(集合、数组等)所产生的元素序列。”集合讲的是数据,流讲的是计算”

注意:① Stream自己不会存储元素。

​ ② Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream。

​ ③ Stream操作是延迟执行的。这意味着他们会等到需要结构的时候才去执行。

2.4.3、创建Stream的方式:

  /*1.可以通过Collection系列集合提供的Stream()或者parallelStream()创建Stre
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值