java8中最大的变化就是引入了Lambda表达式,这是一种函数式编程的方式。
1.lambda表达式的形式
java8的lambda表达式语法如下:
(paramters)->expression;
或者
(parameters)->{statements;};
例如:
()->10;
(x)->x+10;
(x,y)->x+y;
(int x,int y)->x+y;
(int x)->x+10;
或者:
()->{10;}
(x)->{x+10;}
(x,y)->{x+y;}
(int x,int y)->{x+y;}
(int x)->{x+10;}
lambda表达式由三部分组成:
1.parameters:方法中的形参列表,这里的参数是函数式接口里的参数,参数类型可以明确声明也可以隐藏。
2.->:可以理解为“被用于”的意思
3.方法体:可以是表达式也可以是代码块,是函数式接口里方法的具体实现。代码块根据需要使用的方法自行定义是否返回值。
2.lambda表达式的具体实现
2.1 遍历集合
List list= Arrays.asList("lamdbas","Default");
list.forEach(n->{System.out.println(n); System.out.println(n+"23"); });
执行结果如下:
lamdbas
lamdbas23
Default
Default23
2.2带参函数的简写
List list= Arrays.asList("da","abc","c","q","d");
Collections.sort(list,(String a,String b)->{
if(a==null){
return 1;
}else if(b==null){
return -1;
}else{
return a.length()-b.length();
}
});
list.forEach(System.out::println);
执行结果如下
c
q
d
da
abc
简写的依据
能够使用lambda的依据就是必须有相应的函数接口(函数接口,是指内部只有一个抽象方法的接口)。
2.3 自定义函数接口
自定义函数接口很简单,只要编写一个只有一个抽象方法的接口即可。
@FunctionalInterface //自定义函数接口注解,可写可不写,写了会检查是否符合函数接口规范
interface Converter<F,T>{
T convert(F a);
}
//使用lambda表达式调用
Converter<String,Integer> a=str->{System.out.println(str);return Integer.valueOf(str);};
a.convert("1231");
执行结果如下
1231
解释:此功能的主要作用是输出string对象并将string类型的对象转换成Integer;
标准的函数式接口有
- Function<T, R>:接受一个参数T,返回结果R
- Predicate<T>:接受一个参数T,返回boolean
- Supplier<T>:不接受任何参数,返回结果T
- Consumer<T>:接受一个参数T,不返回结果
- UnaryOperator<T>:继承自Function<T, T>,接受一个参数T,返回相同类型T的结果
- BiFunction<T, U, R>:接受两个参数T和U,返回结果R
- BinaryOperator<T>:继承自BiFunction<T, T, T>,接受两个相同类型T的参数,返回相同类型T的结果
- ……
3.方法引用
方法引用式lambda表达式的一种简化写法。具体的结构如下:
Object::methodName
左边式类名或者实例名,中间式方法引用符号"::",右边式相应的方法名,方法引用分为三类:
1.静态方法引用
public class StaticFunction {
@FunctionalInterface
public interface Converter<T,F>{
F convert(T a);
}
static String func(String a){
return a+"abc";
}
@Test
public void test(){
Converter<String,String> a=StaticFunction::func;
System.out.println(a.convert("123"));
}
}
结果如下
123abc
2.实例方法引用
public class StaticFunction {
@FunctionalInterface
public interface Converter<T,F>{
F convert(T a);
}
String func(String a){
return a+"abc";
}
@Test
public void test(){
StaticFunction a=new StaticFunction();
Converter<String,String> b=a::func;
System.out.println(b.convert("123"));
}
}
结果如下
123abc
3.构造方法引用
//创建一个Animal的父类
@Data
public class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void behavior(){
}
}
//创建一个Dog的子类
public class Dog extends Animal{
public Dog(String name,int age){
super(name,age);
}
@Override
public void behavior(){
System.out.println("this is a dog");
}
}
//创建一个Bird的子类
public class Bird extends Animal {
public Bird(String name, int age) {
super(name, age);
}
@Override
public void behavior(){
System.out.println("this is a bird");
}
}
//定义工厂的函数式接口
@FunctionalInterface
interface Factory<T extends Animal>{
T create (String name,int age);
}
//创建测试
@Test
public void test(){
Animal.Factory<Animal> dogFactory=Dog::new;
Animal dog=dogFactory.create("a",1);
if(dog instanceof Dog){
dog.behavior();
}
Animal.Factory<Bird> birdFactory=Bird::new;
Bird bird=birdFactory.create("b",2);
if(bird instanceof Bird){
bird.behavior();
}
}
结果如下
this is a dog
this is a bird
4.lambda的作用域
在lambd表达式外部的局部变量会被JVM隐式的编译成final类型,因此只能访问外而不能修改
public class ReferenceTest {
@Test
public void test() {
int n = 9;
Calculate calculate = param -> {
//n=10; 编译错误
return n + param;
};
calculate.calculate(1);
}
@FunctionalInterface
interface Calculate {
int calculate(int value);
}
}
在lambda表达式内部,对静态变量和成员变量可读可写
public class Reference {
@FunctionalInterface
public interface Refer{
int print();
}
public int count=1;
public static int sum=2;
@Test
public void test(){
System.out.println(count);
System.out.println(sum);
Refer re=()->{
count=3;
sum=4;
return count+sum;
};
System.out.println(re.print());
System.out.println(count);
System.out.println(sum);
}
}
输出结果为
1
2
7
3
4
需要注意的是只有在执行了re.print()这个方法之后成员变量和静态变量的值才会改变。