前言
哈希表在Java中应用非常多
1.8以前,HashMap为数组-链表的形式,但是发送碰撞的概率依旧不低,碰撞意味着低效率;
1.8之后,HashMap改为数组-链表-红黑树的形式。
当满足某些条件(比如链表的节点个数大于8且数组的长度大于64时),就将满足条件的链表(节点个数大于8的)转为红黑树,提高了查询的效率
1. Lambda
Lambada 简介:
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑
记住:函数作为参数传递进方法中
两个东西:函数参数、方法
示例:
匿名类写法
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("hello");
}
}).start();
Lambada写法
new Thread(()->System.out.println("hello")).start();
上述例子:
方法:Thread().start();
函数参数:()->System.out.println(“hello”)
这个函数参数实际上是Runnable中的run函数
编译器会将 “System.out.println(“hello”)” 编译成Runnable.run 的执行指令。
可代码中我们并没有指明Run方法,这是因为 run 方法是Runnable接口的唯一方法,也就是说如果Runable有多个方法是不能使用Lambada表达示的,这种支持Lambada的接口统称函数式接口。
函数参数的写法:
() -> {}
():接口方法的括号,接口方法如果有参数,也需要写参数。若只有一个参数时,括号可以省略。
-> : 分割左右部分。
{} : 要实现的方法体。只有一行代码时,可以不加括号,可以不写return。
2. 函数式接口
必须是 函数式接口 才可以使用lambada 表达示 ,函数式接口笼统的讲就是只有一个抽像方法接口就是函数式接口,其详细特征如下:
- 接口中只有一个抽像方法 会被编译器自动认识成函数式接口
- 有多个方法,但是Object类提供的方法、static和default方法除外
Java8内置的四大核心函数式接口
package concurrency.chapter10;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Consumer<T> 消费型接口
* void accept(T t);
* Consumer<T> andThen(Consumer<? super T> after)
*
* Supplier<T> 供给型接口
* T get();
*
* Predicate<T> 断言型接口
* boolean test(T t);
* default Predicate<T> and(Predicate<? super T> other)
* default Predicate<T> negate()
* default Predicate<T> or(Predicate<? super T> other)
* static <T> Predicate<T> isEqual(Object targetRef)
*
* Function<T,R> 函数型接口
* R apply(T t);
* default <V> Function<V, R> compose(Function<? super V, ? extends T> before)
* default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)
* static <T> Function<T, T> identity() {
* return t -> t;
* }
*
*/
public class test {
static class Money{
// 是否是真钱
final boolean really;
// 钱的数量
final double num;
Money(double num, boolean really){
this.really=really;
this.num=num;
}
public boolean isReally() {
return really;
}
public double getNum() {
return num;
}
}
public static void main(String[] args) {
// 创建钱
final Money money = new Money(100, true);
// 供给--产生对象
System.out.println("小明掏出"+supply(money::getNum)+"元,交给了老板");
// 消费--使用对象
consumed(money,(m)->{
System.out.println("老板收到了"+m.getNum()+"元");
});
//断言型--判断操作
boolean flag = pridicated(money, Money::isReally);
System.out.println("老板查看钱,发现是"+ (flag?"真":"假") +"钱");
//函数型--处理对象
System.out.println(func(flag,m-> m?"老板把硬盘递给了小明":"老板没收了小明的假币,并报了警"));
}
// 消费
public static void consumed(Money money, Consumer<Money> consumer){
consumer.accept(money);
}
// 供给
public static double supply(Supplier<Double> supplier){
return supplier.get();
}
// 断言
public static boolean pridicated (Money money, Predicate<Money> predicate){
return predicate.test(money);
}
// 函数型
public static String func(boolean flag,Function<Boolean,String> function){
return function.apply(flag);
}
}
3. 方法引用与构造器引用
==注意!==这些引用方法的参数列表都需要与函数式接口中的抽象方法参数列表保持一致;
比如说构造器引用,具体引用的哪个构造器,取决于你选择的函数式接口的抽象方法的参数列表
方法引用
package concurrency.chapter10;
import java.util.Arrays;
import java.util.function.*;
/**
* 方法引用:如哦lambda体中已有实现,则可以使用方法引用
* 语法格式:
* 对象::实例方法名
* 类::静态方法名
* 类::实例方法名
*/
public class test2 {
static class User{
String name;
User(String name){
this.name=name;
}
public String getName(){return this.name;};
}
public static void main(String[] args) {
// 类::静态方法
Consumer<String> consumer = System.out::println;
consumer.accept("111");
// 对象::实例方法
User user = new User("testUser");
Supplier<String> supplier = user::getName;
consumer.accept(supplier.get());
// 类::实例方法
/**
* 这种情况比较特殊,当且仅当
* lambda中有两个参数,第一个时实例方法的调用者,第二个是实例方法的参数,
* 这种情况下,可以使用类::实例方法名
*/
BiPredicate<String,String> predicate1 = (x,y)->x.equals(y);
BiPredicate<String,String> predicate2 = String::equals;
}
}
构造器引用
ClassName::new
选择的哪个构造器,将与抽象方法的参数进行匹配
数组引用
Type[]::new
Function<Integer,User[]> function = User[]::new;
User[] users = function.apply(5);
未完待续