java 1.8 相对于java 1.7修改了很多地方,增加了很多新特性.
Lambda表达式的格式:
Interface in = Lambda表达式.
注意:
1.左边一定是一个接口,抽象类也不行,因为Lambda表达式就是设计来实现这个接口的方法的匿名内部类
2.左边的这个接口一定是只有一个抽象方法的函数式接口.因为如果有多个接口,则这个Lambda表达式则不能区分是实现的哪个抽象方法.
3.这个函数式接口可以用注解@FunctionalInterface修饰.
函数式接口,例如:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
java 8 中引入了一个新的操作符 “->” ,该操作符称为箭头操作符或lambda操作符,他把Lambda表达式分成了两部分:
(1) 无参数,无返回值
/**
* 无参无返回值
*/
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("haha");
}
};
r1.run();
System.out.println("-----------");
//Lambda表达式
Runnable r2 = () -> System.out.println("哈哈");
r2.run();
}
(2) 有1个参数,无返回值
/**
* 有1个参数,无返回值
* x : 参数 1
*/
@Test
public void test2() {
//Consumer { void accept(T t); }
Consumer<String> consumer = (x) -> System.out.println(x); //格式1
Consumer<String> consumer2 = x -> System.out.println(x + "哈哈"); //格式2
consumer.accept("祖国万岁");
consumer2.accept("天下第一");
}
(3) 有多个参数,并且有多条Lambda体语句,且有返回值
/**
* 有一个或者多个参数,并且有多条Lambda体语句,且有返回值
* 必须用大括号,包裹Lambda体,并且有return语句.
*/
@Test
public void test3(){
//Comparable { public int compareTo(T o); }
Comparable<Integer> com = (x) -> {
System.out.println("哈哈");
return Integer.compare(1,x);
};
int i = com.compareTo(0);
System.out.println(i);
}
(4) 有 1个或者多个参数,并且Lambda 体只有一条语句,无论是否有返回值
/**
* 有多个参数,并且只有条Lambda体语句,且有返回值
* 可以省略大括号,省略return语句
*/
@Test
public void test4(){
Comparable<Integer> com = (x) -> Integer.compare(1,x);
int i = com.compareTo(0);
System.out.println(i);
}
总结:
左右遇一,括号省
左侧推断,类型省
能省就省.解释:
1.左右遇一:一,表示的是1个参数,则省略小括号,或者是Lambda体中只有1条语句,则省略大括号和return关键字.
2.Lambda 的参数列表的参数类型可以不用写.因为JVM的编译器可以根据上下文推断出参数类型.
java 8中内置了几大函数式接口,减少了我们自定义函数式接口的编写.内置的函数式接口主要分为以下4大类.
接口:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
应用:
@Test
public void test2() {
//Consumer { void accept(T t); }
Consumer<String> consumer = (x) -> System.out.println(x); //格式1
Consumer<String> consumer2 = x -> System.out.println(x + "哈哈"); //格式2
consumer.accept("祖国万岁");
consumer2.accept("天下第一");
}
@FunctionalInterface
public interface Supplier<T> {
T get();
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
方法引用: 若Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用" (可以理解为方法引用是Lambda 表达式的另外一种表现形式)
(1) 方法引用
/**
* 对象::实例方法名
* 接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
*/
@Test
public void test1(){
//demo1
// void accept(T t);
PrintStream stream = System.out;
Consumer<String> con = (x) -> stream.println(x);
con.accept("哈哈");
//可以简写
Consumer<String> con2 = System.out::println;
con2.accept("我爱祖国!!");
//demo2
//T get();
Employee employee = new Employee(12,"张三",14,888.0);
Supplier<String> sup = () -> employee.getName();
System.out.println(sup.get());
//简化
Supplier<String> sup2 = employee::getName;
System.out.println(sup2.get());
}
/**
* 类::静态方法名
* 接口中的方法的参数和返回值必须和引用方法的参数和返回值相同
*/
@Test
public void test2(){
//int compare(T o1, T o2);
Comparator<Integer> com1 = (x,y) -> Integer.compare(x,y);
//简化
Comparator<Integer> com = Integer::compare;
}
/**
* 类::实例方法名
* 参数列表中的第一蚕食是实例方法的调用者,第二个参数是实例方法的参数.则可以使用这种方式
*/
@Test
public void test3(){
// boolean test(T t, U u);
BiPredicate<String,String> bi = (x,y) -> x.equals(y);
System.out.println(bi.test("a","a"));
//简化
BiPredicate<String,String> bi2 = String::equals;
System.out.println(bi2.test("a","ab"));
}
(2) 构造器引用
格式:
类::new
函数式接口的参数需要和构造方法的参数一样,并且函数式接口的返回值和该类类型一致.
/**
* 构造器引用
* 函数式接口的参数需要和构造方法的参数一样,并且函数式接口的返回值和该类类型一致.
*/
@Test
public void test4(){
//demo1 无参的构造方法 public Employee() {}
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
//简化,构造器引用
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
//demo2 一个参数的构造方法 public Employee(Integer id) { this.id = id; }
Function<Integer,Employee> fun1 = (x) -> new Employee(x);
System.out.println(fun1.apply(11));
//构造器简化
Function<Integer,Employee> fun2 = Employee::new;
System.out.println(fun2.apply(22));
}
(3) 数组引用
格式:
type[]::new
注意:
1.函数式接口的方法必须为两个参数,且第一个参数必须为integer类型,他代表数组的长度;第二个为数组类型,他代表数组的类型
2.type包括基本类型和引用类型
/**
* 数组引用
* 函数式接口的方法必须为两个参数,且第一个参数必须为integer类型,他代表数组的长度;第二个为数组类型,他代表数组的类型
*/
@Test
public void test5(){
Function<Integer,String[]> fun = (x) -> new String[x];
System.out.println(fun.apply(3).length);
//数组引用简化 ,第一个参数必须为integer类型,因为这个是数组的长度
Function<Integer,String[]> fun2 = String[]::new;
System.out.println(fun2.apply(4).length);
}
demo1
(1) 自定义函数式接口
/**
* @author gl
* @time 2020-07-10 0:21
* @function : 函数式接口,只有一个抽象方法的接口
* @step :
*/
@FunctionalInterface //这个修饰的接口就是函数式接口
public interface MyInterface {
Integer getValue(Integer number);
}
(2) 自定义方法
/**
* 这个就是使用的策略模式
* @param num 参数
* @param myInterface 这是定义了一个计算的策略接口的参数,具体什么策略,自己实现
*/
public Integer calculate(Integer num,MyInterface myInterface){
return myInterface.getValue(num);
}
(3) 业务中自己使用不同的策略
/**
* 使用策略模式,外加Lambda表达式
*/
@Test
public void test6(){
Integer value = calculate(2, x -> 2 * x);
System.out.println(value);
System.out.println(calculate(3,x -> x * x));
}