一、Lambda表达式
lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码
例子:筛选不同价格商品信息
1.定义商品对象
@Data
public class Product {
private Double price;
private String color;
}
2.定义一个MyPredicate接口
public interface MyPredicate <T> {
boolean test(T t);
}
3.定义过滤方法及lambda
public class lambda {
// 定义过滤方法:
public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){
List<Product> prods = new ArrayList<>();
for (Product prod : list){
if (mp.test(prod)){
prods.add(prod);
}
}
return prods;
}
// 使用lambda表达式进行过滤
@Test
public void test4(){
List<Product> proList = new ArrayList<>();
Product product = new Product();
product.setPrice((double) 7000);
product.setColor("黑色");
proList.add(product);
product = new Product();
product.setPrice((double) 9000);
product.setColor("蓝色");
proList.add(product);
// 使用lambda表达式进行过滤
List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);
for (Product pro : products){
System.out.println(pro);
}
}
}
当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念
二、函数式接口
函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface
常见的四大函数式接口:
1.Consumer 《T》:消费型接口,有参无返回值
@Test
public void test(){
changeStr("hello",(str) -> System.out.println(str));
}
/**
* Consumer<T> 消费型接口
* @param str
* @param con
*/
public void changeStr(String str, Consumer<String> con){
con.accept(str);
}
2.Supplier 《T》:供给型接口,无参有返回值
@Test
public void test2(){
String value = getValue(() -> "hello");
System.out.println(value);
}
/**
* Supplier<T> 供给型接口
* @param sup
* @return
*/
public String getValue(Supplier<String> sup){
return sup.get();
}
3.Function 《T,R》::函数式接口,有参有返回值
@Test
public void test3(){
Long result = changeNum(100L, (x) -> x + 200L);
System.out.println(result);
}
/**
* Function<T,R> 函数式接口
* @param num
* @param fun
* @return
*/
public Long changeNum(Long num, Function<Long, Long> fun){
return fun.apply(num);
}
4.Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型
public void test4(){
boolean result = changeBoolean("hello", (str) -> str.length() > 5);
System.out.println(result);
}
/**
* Predicate<T> 断言型接口
* @param str
* @param pre
* @return
*/
public boolean changeBoolean(String str, Predicate<String> pre){
return pre.test(str);
}
总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了。
(上文中的MyPredicate可以替换成Predicate断言接口)
二、Stream API
甚至不用定义过滤方法,直接在集合上进行操作
// 使用jdk1.8中的Stream API进行集合的操作
@Test
public void test(){
// 根据价格过滤
proList.stream()
.fliter((p) -> p.getPrice() <8000)
.limit(2);
proList.forEach(System.out::println);
// 根据颜色过滤
proList.stream()
.fliter((p) -> "红色".equals(p.getColor()));
proList.forEach(System.out::println);
// 遍历输出商品名称
proList.stream()
.map(Product::getName);
proList.forEach(System.out::println);
}
三、对hashMap等map集合的数据结构优化
在jdk1.8中对hashMap等map集合的数据结构优化。hashMap数据结构的优化
原来的hashMap采用的数据结构是哈希表(数组+链表),hashMap默认大小是16,一个0-15索引的数组,如何往里面存储元素,首先调用元素的hashcode方法,计算出哈希码值,经过哈希算法算成数组的索引值,如果对应的索引处没有元素,直接存放,如果有对象在,那么比较它们的equals方法比较内容如果内容一样,后一个value会将前一个value的值覆盖,如果不一样,在1.7的时候,后加的放在前面,形成一个链表,形成了碰撞,在某些情况下如果链表无限下去,那么效率极低,碰撞是避免不了的加载因子:0.75,数组扩容,达到总容量的75%,就进行扩容,但是无法避免碰撞的情况发生。
在1.8之后,用数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入除了添加之后,效率都比链表高。
1.8之后链表新进元素加到末尾ConcurrentHashMap (锁分段机制),concurrentLevel,jdk1.8采用CAS算法(无锁算法,不再使用锁分段),数组+链表中也引入了红黑树的使用。