主要内容
目录
1.Lambda表达式
2.函数式接口
3.方法引用与构造器引用
4.Stream API
5.接口中的默认方式与静态方法
6.新时间日期API
7.其他新特性
优点:1.速度更快(对底层的数据结构做了一定的更新和改动,对内存结构也做了一定的改变) 2.代码更少(Lambda)3.强大的Stream API 4.便于并行 5.最大化减少空指针异常
Java8对于HashMap的改变
JDK1.8之前HashMap:数组-链表
JDK1.8之后HashMap:数组-链表-红黑树(当碰撞个数大于8时,并且HashMap总容量大于64,链表变红黑树)-->红黑树除添加操作,其他操作的效率都变高
注意:负载因子为0.75最好
Lambda表达式
Lambda是一种匿名函数
匿名类 比较 Lambda表达式(1)
//匿名类
Comparator<Integer> com=new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
//Lambda表达式
Comparator<Integer> com1=(o1,o2)->Integer.compare(01, 02);
TreeSet<Integer> ts=new TreeSet<>(com);
TreeSet<Integer> ts2=new TreeSet<>(com);
匿名类 比较 Lambda表达式(2)
public interface Mypredicate <T>{
abstract boolean Filter(Employee employee);
}
public List<Employee> filterEmployee(List<Employee> list, Mypredicate<Employee> mp) {
List<Employee> employees = new ArrayList<>();
for (Employee employee : list) {
if (mp.Filter(employee)) {
employees.add(employee);
}
}
return employees;
}
@Test
public void test1() {
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 999),
new Employee("李四", 19, 929),
new Employee("王五", 20, 123));
//匿名内部类
List<Employee> list = filterEmployee(employees, new Mypredicate<Employee>() {
@Override
public boolean Filter(Employee employee) {
return employee.getAge() < 20;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
//Lambda表达式
List<Employee> list1=filterEmployee(employees,(e)->e.getAge()<20);
list1.forEach(System.out::println);
//Stream API
employees.stream().filter(employee -> employee.getAge()<20).forEach(System.out::println);
}
其中区别Filter和filter,filter是Stream的方法,Filter是自定义的方法
Lambda表达式基础语法
Java8中引入了一个新的操作符" ->",该操作符成为箭头操作符或者Lambda操作符,将Lambda表达式拆分为两位部分:左侧和右侧。
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体
语法格式一:无参数,无返回值:
()->System.out.println("Hello Lambda");
@Test
public void test2(){
Runnable r=new Runnable() {
@Override
public void run() {
System.out.println("hello world!");
}
};
r.run();
//Lambda表达式
Runnable r1=()-> System.out.println("hello world1!");
r1.run();
}
语法格式二:有一个参数,并且无返回值
(x)-> System.out.println(x);
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
@Test
public void test3(){
Consumer<String> consumer=(x)-> System.out.println(x);
consumer.accept("中国计量大学牛逼!");
}
其中(x)-> System.out.println(x)是对accept方法的实现
若Lambda只有一个参数,小括号可以不写
x-> System.out.println(x)
语法格式三:有两个以上的参数,有返回值,并且Lambda体中有多条语句,必须使用大括号
Comparator<T>中有int compare(T o1, T o2)方法
@Test
public void test4(){
Comparator<Integer> comparable=(x, y)->{
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}
格式语法四:若Lambda体中只有一条语句,return和大括号都可以不写
@Test
public void test5(){
Comparator<Integer> comparable=(x, y)->Integer.compare(x,y);
}
语法格式五:Lambda表达式的参数列表的数据类型可以写(但都要加),也可以省略,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
@Test
public void test5(){
//不省略数据类型
Comparator<Integer> comparator=(Integer x, Integer y)->Integer.compare(x,y);
Comparator<Integer> comparable1=(x, y)->Integer.compare(x,y);
}
总结:Lambda表达式的实现需要“函数式接口”的支持。函数式接口就是只有一个抽象方法的接口。函数式接口可以使用@FunctionalInterface修饰,该注解可以检查是否是函数式接口。Comparator中虽然有很多方法,但只有一个抽象方法,所以也是函数式接口。
应用
@FunctionalInterface
public interface MyFunction {
String getValue(String str);
}
public String strHandler(String str, MyFunction mf){
return mf.getValue(str);
}
@Test
public void test7(){
String trim=strHandler("\t\t\t 中国计量大学 ", str->str.trim());
System.out.println(trim);
String newStr=strHandler("sahjdhaskj",str -> str.toUpperCase());
System.out.println(newStr);
}
Java8内置的四大核心函数式接口
Comsumer<T>: 消费型接口
void accept(T t);
Supplier<T>:供给型接口
T get();
Function<T,R>:函数型接口
R apply(T t);
Predicate<T>:断言型接口
boolean test(T t);
例如
//消费
public void happy(double money,Consumer<Double> con){
con.accept(money);
}
@Test
public void test8(){
happy(100,x-> System.out.println(x));
}
//供给
public List<Integer> provide(int num,Supplier<Integer> supplier){
List<Integer> list=new ArrayList<>();
for(int i=0;i<num;i++){
Integer integer = supplier.get();
list.add(integer);
}
return list;
}
@Test
public void test9(){
List<Integer> provide = provide(3, () -> (int)(Math.random()* 100));
System.out.println(provide);
}
//函数
public int Length(String str,Function<String,Integer> function){
return function.apply(str);
}
@Test
public void test10(){
int length = Length("213432", x -> x.length());
System.out.println(length);
}
//断言
public Boolean Check(int age,Predicate<Integer> fun){
return fun.test(age);
}
@Test
public void test11(){
Boolean flag=Check(20,x->x>10);
System.out.println(flag);
}
方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”。(可以理解为方法引用是Lambda表达式的另外一种表现形式)
使用前提注意:
1.Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型一致!
2.若Lambda参数列表中 第一个参数为实例方法的调用者,第二个参数为实例方法的参数时,这时就可以使用 类::实例方法。
语法格式一 : 对象::实例方法名
@Test
public void test1(){
//println属于实例方法
Consumer<String> con=(x)-> System.out.println(x);
PrintStream ps1=System.out;
Consumer<String> con1=(x)-> ps1.println(x);
//Lambda体中的特定功能已经有特定方法(一般只有一行代码)可以完成时,就可以选择另外一种表现形式
//函数型接口抽象方法的入参和出参,要与引用方法的入参和出参一致。
Consumer<String> con2=ps1::println;
//等价于Consumer<String> con1= System.out::println(x);
con2.accept("123");
}
原因:System.out的public void println(String x)方法和Consumer<String>的void accept(String t)方法的入参和出参一致,且accept方法属于实例方法,所以可以使用 对象::实例方法名。
@Test
public void test2(){
Employee employee=new Employee("小王",12,231);
//Lambda表达式
Supplier<String> sup=()->employee.getName();
//方法引用
Supplier<String> sup1=employee::getName;
String s = sup1.get();
System.out.println(s);
}
原因:employee的public String getName()方法和Suppliers<String>的T get()方法的入参和出参一致,且get方法属于实例方法,所以可以使用 对象::实例方法名。。
语法格式二: 类::静态方法名
@Test
public void test3(){
//Lambda表达式
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
//方法引用,compare为静态方法
Comparator<Integer> com1=Integer::compare;
}
原因:Comparator<Integer>的int compare(T o1, T o2);方法和Integer的public static int compare(int x, int y)方法的入参和出参一致,且compare方法为静态方法,所以可以使用 类:: 静态方法名。
语法格式三: 类::实例方法名
第一个参数为这个实例方法的调用者,第二个参数为这个实例方法的参数时,就可以使用 类::实例方法。
@Test
public void test4(){
BiPredicate<String,String> biPredicate=(x,y)->x.equals(y);
//第一个参数为这个方法的调用者,第二个参数为这个方法的参数时,这时就可以使用 类::实例方法
BiPredicate<String,String> biPredicate1=String::equals;
}
构造器引用
注意:需要调用的构造器参数列表要与函数式接口中的抽象方法参数列表保持一致
语法格式: 类::new
public Employee() {
}
public Employee(String name) {
this.name = name;
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
@Test
public void test5(){
//Lambda表达式
Supplier<Employee> supplier=()->new Employee();
//类::new (无参构造器)
Supplier<Employee> supplier1=Employee::new;
//不能使用Supplier是因为Supplier中的get方法是无参的,若使用(x)->new Employee()则报错
Function<String,Employee>function=(x)->new Employee(x);
//类::new (调用的是有一个参数为String的构造函数)
Function<String,Employee>function1=Employee::new;
BiFunction<String,Integer,Employee> biFunction=(x,y)->new Employee(x,y);
//类::new (调用的是有一个参数为String,另一个参数为Integer的构造函数)
BiFunction<String,Integer,Employee> biFunction1=Employee::new;
//本质:new的构造类型取决于函数式接口抽象方法的参数列表
}
数组引用
语法格式:Type[] :: new;
@Test
public void test6(){
Function<Integer,String[]> function=(x)->new String[x];
Function<Integer,String[]> function1=String[]::new;
}
Junit
主要用来程序员测试,即所谓的白盒测试(单元测试),例如加@Test注解需要Junit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>