一、入门示例
代码git地址:gitee.com/ggg/TestJav…
需求:有一堆苹果,这些苹果的颜色不同、大小不一。现在要从中筛选出黄色的苹果。
public class Apple {
private String color;
private Integer weight;
....省略get set toString 方法
}
1.采用硬编码的方式
public class AppleFilterTest {
private static List<Apple> apples;
@BeforeClass
public static void initApples(){
apples = Arrays.asList(
new Apple("red",1),
new Apple("yellow",2),
new Apple("black",3),
new Apple("green",2)
);
}
@Test
public void filterApples1(){
List<Apple> appleList = filterApplesByColor(apples);
for (Apple apple : appleList) {
System.out.println(apple);
}
}
private List<Apple> filterApplesByColor(List<Apple> apples){
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if("yellow".equals(apple.getColor())){
result.add(apple);
}
}
return result;
}
缺陷,需求一旦变更,就需要去修改原来的代码,灵活性太差。比如,现在的需求变为需要筛选出红色的苹果。
2.采用参数传递
@Test
public void filterApples2(){
List<Apple> appleList = filterApplesByColor1(apples,"red");
for (Apple apple : appleList) {
System.out.println(apple);
}
}
缺陷,如果需求变更为根据重量去筛选,也需要去修改代码。
3.采用策略模式
@Test
public void filterApples3(){
List<Apple> appleList = filterApples(apples,new PredicateByColor("red"));
for (Apple apple : appleList) {
System.out.println(apple);
}
}
public class PredicateByColor implements MyPredicate<Apple>{
private String color;
public PredicateByColor(String color) {
this.color = color;
}
@Override
public boolean test(Apple e) {
return e.getColor().equals(color);
}
}
public interface MyPredicate<T> {
boolean test(T e);
}
这种方式看似很完美了,如果需求变更,只需要去实现MyPredicate接口,还有没有更好的呢?
4.采用匿名内部类
@Test
public void filterApples4(){
List<Apple> appleList = filterApples(apples, new MyPredicate<Apple>() {
@Override
public boolean test(Apple e) {
return "red".equals(e.getColor());
}
});
for (Apple apple : appleList) {
System.out.println(apple);
}
}
匿名内部类减少了类的数量,还有没有更好的呢?
5.采用函数式
@Test
public void filterApples5(){
List<Apple> appleList = filterApples(apples, e -> "red".equals(e.getColor()));
for (Apple apple : appleList) {
System.out.println(apple);
}
}
函数式,将函数作为参数传递到方法中,这样代码看起更简洁。其实Java中的函数式和匿名类在JVM层面是有不同实现的,具体可采用javap去查看生成的字节码。
二、Java Lambda语法
1.Lambda操作符(也可称为箭头符号)
->
箭头符号左侧:参数列表
箭头符号右侧:方法体
()->{}
2.方法分类
2.1 无参、无返回值
@Test
public void test1() {
//普通写法
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("------1-----");
}
};
r.run();
System.out.println("---------------------------");
//函数式写法
Runnable r2 = () -> System.out.println("------2------");
r2.run();
System.out.println("---------------------------");
//方法体要是多行,需要加上 {}
Runnable r3 = () -> {
System.out.println("------2------");
System.out.println("------2------");
};
r3.run();
}
2.2 无参、有返回值
@Test
public void test2(){
// 普通写法
Supplier<Integer> supplier = new Supplier<Integer>() {
@Override
public Integer get() {
return 100;
}
};
System.out.println(supplier.get());
System.out.println("-------------");
//函数式写法
supplier=()->{
System.out.println("******");
return 110;
};
System.out.println(supplier.get());
}
2.3有参、无返回值
@Test
public void test3() {
//非Lambda写法
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("-----" + s + "---------");
}
};
System.out.println("----------一个参数、无返回值的普通写法------------");
consumer.accept("hello");
//如果只有一个参数,箭头符号左边的小括号可以省略
Consumer<String> consumer2 = s -> System.out.println("-----" + s + "---------");
System.out.println("----------一个参数、无返回值的Lambda写法------------");
consumer.accept("hello");
//有两个或者多个参数
BiConsumer<Integer,String> biConsumer= (integer, s) -> System.out.println("---integer="+integer+"-----s=" + s + "---------");
biConsumer.accept(1,"aa");
}
2.4有参、有返回值
@Test
public void test4(){
//如果方法体中是一行代码,可以省略{}、return 省略大括号之后加上return 还会报错,所以大括号和return都不能写.
Comparator<Integer> comparator= (x,y) -> Integer.compare(x,y);
System.out.println(comparator.compare(1,6));
//方法体中多行代码,不能省略{},return 也不能省略
Comparator<Integer> comparator2= (x,y) -> {
System.out.println("--------");
return Integer.compare(x,y);
};
System.out.println(comparator2.compare(10, 9));
}
三、JAVA8内置四大核心函数式接口
1.Consumer void accept(T t); 有参数 无返回值
2.Supplier T get();无参数 有返回值
3.Predicate boolean test(T e);有参数 返回值为boolean类型
4.Function<T, R> R apply(T t);有参数 有返回值
这四个函数式接口,能满足我们的很多场景,减少了我们自定义函数式接口。
四、方法引用和构造器引用
1.方法引用
1.1 实例方法引用
1.2 静态方法引用
2.构造器引用
2.1 无参
2.2 有参