JDK8 函数式编程 Lambda表达式
简单应用
内部对象的简写
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("鲁班1");
}
}).start();
//效果与使用lambda表达式是一样的
new Thread(() -> System.out.println("鲁班2")).start();
}
Output:
鲁班1
鲁班2
传递函数作为参数
- 使用Lambda表达式构成函数的参数 Fucntion
public static void main(String[] args) {
System.out.println(doSomething(a->Integer.parseInt(a),"123"));
}
public static Integer doSomething(Function<String, Integer> function, String args) {
return function.apply(args);
}
Output:
123
- 首先构建一个Apple类
public class Apple {
private Integer age;
private String name;
public Apple(Integer age, String name) {
this.age = age;
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Apple{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
- 最简单且熟悉的操作方案
public class AppleServer {
private static ArrayList<Apple> apples = new ArrayList<Apple>();
public static void main(String[] args) {
apples.add(new Apple(1, "xia"));
apples.add(new Apple(12, "jian"));
apples.add(new Apple(123, "bing"));
System.out.println(getAppleByName("xia"));
}
public static ArrayList<Apple> getAppleByName(String name) {
ArrayList<Apple> res = new ArrayList<Apple>();
for (Apple apple : apples) {
if (apple.getName().equals(name)) {
res.add(apple);
}
}
return res;
}
}
- 使用Lambda函数构成选择逻辑 Predicate
public static void main(String[] args) {
apples.add(new Apple(1, "xia"));
apples.add(new Apple(12, "jian"));
apples.add(new Apple(123, "bing"));
System.out.println(getApple(a->a.getAge()<100 && a.getName().contains("a")));
}
public static ArrayList<Apple> getApple(Predicate<Apple> predicate) {
ArrayList<Apple> res = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple)) {
res.add(apple);
}
}
return res;
}
使用Stream优化遍历
public static ArrayList<Apple> getApple(Predicate<Apple> predicate) {
ArrayList<Apple> res = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple)) {
res.add(apple);
}
}
// 使用下面的stream可以直接遍历list
res = (ArrayList<Apple>) apples.stream().filter(predicate).collect(Collectors.toList());
return res;
}
使用Lambda表达式实现简单的函数功能:apply
public class MyFunction {
public static void main(String[] args) {
// 使用Lambda实现简单的函数
Function<String, String> f = t -> "In Lambda "+t;
System.out.println(f.apply("name"));
}
}
自定义函数式接口
使用Lambda表达式实现接口函数
定义接口类
- 使用@FunctionalInterface
- 接口中只能存在唯一的非Object类的抽象方法
- 如果想要添加其他的方法,那么需要添加default声明,同时该方法要在接口中被实现
@FunctionalInterface
public interface MyFunction {
void sayHello();
String toString();
default void defaultFuntion(){
}
}
使用Lambda表达式实现接口函数
public class MyFunction {
public static void main(String[] args) {
// 使用方法1 普通方法实现接口函数
MyFunctionInterface myFunctionInterface1 = new MyFunctionInterface() {
@Override
public void sayHello(String name) {
System.out.println(name+"Hello1");
}
};
//使用方法2 Lambda表达式实现接口函数
MyFunctionInterface myFunctionInterface2 = (name) -> {
System.out.println(name+"Hello2");
};
myFunctionInterface1.sayHello("xia1");
myFunctionInterface2.sayHello("xia2");
}
}
引用
基于实例方法的引用
给一个实例的方法添加引用
public class ReferenceLambda {
// 基于实例方法的引用
public String sayHello(String name) {
System.out.println(name + ":say Hello");
return name + ":say Hello";
}
@Test
public void test1() {
ReferenceLambda referenceLambda = new ReferenceLambda();
Function<String, String> f = referenceLambda::sayHello;
f.apply("test1基于实例方法的引用");
}
}
基于构造方法的引用
这个引用其实是一个对象,暂时还不知道怎么使用!
// 基于构造方法的引用
public interface MyLove1 {
String getLove();
}
@Test
public void test2() {
MyLove1 f = String::new; //使用String的构造方法是因为getLove的返回类型是String
f.getLove();
}
基于第一个参数的类型的引用
这个引用其实也是一个对象,其接口中被实现的方法是来自于接口函数中的第一个参数的类型的非静态方法
// 基于第一个参数的类型的引用
public interface MyLove3 {
int getLove(String s1, String s2);
}
@Test
public void test3() {
//使用String是因为getLove的第一个参数是String类型
//能够匹配上还有一个重要原因是compareTo的返回类型是int类型,与getLove返回类型相同
//使用第一个参数s1的compareTo方法,并将s2作为compareTo的参数,返回值就是int类型
MyLove3 f = String::compareTo;//非静态方法
System.out.println(f.getLove("aa", "aa"));
}
基于静态方法的引用
与上面一样,这个引用其实也是一个对象,其接口中被实现的方法是来自于接口函数中的第一个参数的类型的静态方法,而不是非静态方法。
// 基于静态方法的引用
public interface ToInteger {
int toInt(String str);
}
@Test
public void test4() {
ToInteger toi = Integer::valueOf; //静态方法
System.out.println(toi.toInt("1"));
}
排序
- 传统排序的方法
- 使用Lambda表达式实现接口Comparator
- 使用Stream加速,filter筛选,sorted排序
public class SortTest {
public static void main(String[] args) {
ArrayList<Apple> apples = new ArrayList<>();
apples.add(new Apple(21, "xia"));
apples.add(new Apple(12, "jian"));
apples.add(new Apple(123, "bing"));
//传统排序方法
Collections.sort(apples, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getAge() - o2.getAge();
}
});
//Lambda 排序
Collections.sort(apples, (o1, o2) -> o1.getAge() - o2.getAge());
//基于Stream排序
ArrayList<Apple> res= (ArrayList<Apple>) apples.stream()
.filter(a -> a.getName().contains("a")).
sorted((o1, o2) -> o1.getAge() - o2.getAge()).
collect(Collectors.toList());
System.out.println(res);
}
}
Stream
forEach
- forEach方法可以将循环内部放进参数内
ArrayList<Apple> apples = new ArrayList<>();
apples.add(new Apple(21, "xia"));
apples.add(new Apple(12, "jian"));
apples.add(new Apple(123, "bing"));
for (Apple apple : apples) {
System.out.println(apple);
}
apples.stream().forEach(System.out::println);
apples.stream().forEach((t)-> System.out.println(t)); // 这三种方法都可以