简介
- 函数式编程是把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。
- 比如一个功能(方法)很多地方用,在要用的类都创建不现实,而单独为其创建一个类也不现实。根据面向对象思想,如果很多种不同功能的方法都单独创建一个类很臃肿。这时内部类和函数式编程就非常简洁高效
- lambda就是快速实现一个接口的方法,然后把该方法以对象形式传入其他方法
- 我们把只定义了单方法的接口称之为
FunctionalInterface
,用注解@FunctionalInterface
标记。(即只有一个方法的接口。如果接口有很多方法,但是只有一个抽象方法,也算单方法接口)- 在java8后,注意接口中的
**default**
方法和**static**
不算抽象方法
- 在java8后,注意接口中的
- 该注解表明接口为函数式接口,函数式接口才可以使用Lambda
Lambda表达式
Lambda表达式是JDK8的重要特性之一。使用简洁清晰的表达式来表达一个接口,同时也简化了对集合,数组数据的一系列操作
Lambda表达式语法如下:([数据类型 参数名,数据类型 参数名,...]) -> {表达式主体}
- ()内为接口抽象方法需要的参数;数据类型可以省略 ; 只有一个参数时,括号也可以省略
- ->表示Lambda表达式箭牌,用于指定参数数据指向
- 表达式主体为接口中抽象方法的具体实现,如果只有一条语句,可以省略
**{}**
- 只有一条return时,可以省略return
前面内部类中讲过匿名内部类可以简化接口,而Lambda表达式比匿名内部类还要简化。**Lambda表达式可以省略**``_**参数**_``**和**``_**返回值**_``**的类型还有**``_**类名**_``**,编译器会自动推断**
缺点:接口有且只有一个抽象方法时才可以使用Lambda表达式代替匿名内部类
interface Animal {
void shout();
}
//--------------------------------------------------------
public class T {
public static void main(String[] args) {
String name = "小花";
//匿名内部类写法:
animalShout(new Animal() { //匿名内部类
public void shout() {
System.out.println(name);
}
}
);
//lambda写法:
animalShout(() -> System.out.println(name)); //Lambda表达式
}
public static void animalShout(Animal an) { an.shout(); }
}
String[] array = ...
Arrays.sort(array, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
//ladmda写法:
Arrays.sort(array, (s1, s2) -> {
return s1.compareTo(s2);
});
//或者再简化:
Arrays.sort(array, (s1, s2) -> s1.compareTo(s2) );
lambda中的变量规则
- 如果lambda中使用lambda表达式外面的方法中的局部变量,则该变量必须是不可变的。即静态变量和类变量不受影响
- lambda中的变量名不能与所在方法里的局部变量重名,域变量和静态变量不受限制
lambda中可使用 this、super 关键字,等同于在所在方法里方法中使用
- 注意不能使用super访问父接口中的default方法。这是接口的限制跟lambda没关系 ```java public class AClass { private Integer num1 = 1; private static Integer num2 = 10;
public void testA() {
int a = 1; int b = 2; int c = 3; a++; new Thread(() -> { System.out.println("a=" + a); // 在 Lambda 表达式使用前有改动,编译报错 b++; // 在 Lambda 表达式中更改,报错 System.out.println("c=" + c); // 在 Lambda 表达式使用之后有改动,编译报错 System.out.println("num1=" + this.num1++); // 对象变量,或叫类/域变量,编译通过 AClass.num2 = AClass.num2 + 1; System.out.println("num2=" + AClass.num2); // 静态变量,编译通过 }).start(); c++;
} }
System.out.println("subClass: hello budy!");
}
@Override public void printName(String name) {
System.out.println("subClass: name=" + name);
}
public void testA() {
this.printHello(); // 输出:subClass: hello budy! super.printName("susu"); // 输出:ParentClass: name=susu new Thread(() -> { this.printHello(); // 输出:subClass: hello budy! super.printName("susu"); // 输出:ParentClass: name=susu }).start();
} }
class ParentClass { public void printHello() { System.out.println(“ParentClass: hello budy!”); }
public void printName(String name) { System.out.println(“ParentClass: name=” + name); } }
<a name="imrCG"></a>
# 方法引用
- **方法引用即是普通的lambda表达式基础上更加精简的功能,方法引用的标志就是使用了**`**::**`
- **方法引用还可以将已存在的方法作为参数进行传递,不必像普通的lambda一样每次写个lambda方法**
- **即方法已存在,才能使用方法引用。方法不存在只能用lambda创建一个**
- 方法引用**,如果某个方法签名和函数式接口的抽象方法恰好一致**,就可以直接传入方法引用。
- 因为Comparator<String>接口定义的方法是int compare(String, String),和静态方法int cmp(String, String)相比,除了方法名外,方法参数一致,返回类型相同,因此,我们说两者的方法签名一致,可以直接把方法名作为Lambda表达式传入
- 实例方法都有一个隐藏参数`this`,下面的`compareTo(s2)`就相当于`compareTo(this,s2)`所以方法签名与`Comparator的compareTo`相同
---
- 静态方法引用`类名::静态方法名`等同于提供了方法参数的lambda
- 实例方法引用`对象::实例方法名` 等同于提供了方法参数的lambda
- 等同于提供了方法参数的lambda比如:`System.out::println相当于System.out.println(x)`
`Math::pow相当于(x, y) -> Math.pow(x, y)`
- 构造方法引用`类名::new`
- 实例方法引用`类名::实例`
- 这种情况第一个参数会成为执行方法的对象,比如`(x, y) -> x.compareToIgnoreCase(y)`
- 还可以使用this,super进行方法引用,同普通方法里使用一样的效果,如`this::equals相当于x -> this.equals(x)``super::实例方法`
```java
list.forEach(System.out::println);
//---------相当于
Consumer<Integer> consumer = System.out::print; // accept(T t)
list.forEach(consumer);
//引用静态方法
public class Main {
public static void main(String[] args) {
String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, Main::cmp);
System.out.println(String.join(", ", array));
}
static int cmp(String s1, String s2) {
return s1.compareTo(s2);
}
}
//引用实例方法
public class Main {
public static void main(String[] args) {
String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, String::compareTo);
System.out.println(String.join(", ", array));
}
}
//引用静态方法,快速将List<String> 注入到List<Person>中
public class Main {
public static void main(String[] args) {
List<String> names = List.of("Bob", "Alice", "Tim");
List<Person> persons = names.stream().map(Person::new).collect(Collectors.toList());
System.out.println(persons);
}
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
public String toString() {
return "Person:" + this.name;
}
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
把泛型对应上就是方法签名Person apply(String),即传入参数String,返回类型Person。而Person类的构造方法恰好满足这个条件,
四大函数式接口
下面这几个接口就是为了帮助非函数式接口的方法作为参数传递的,这些接口的核心函数式方法相当于被替换为了我们传递的任意方法
Consumer
消费型接口 有参无返回,只吃不拉。接口核心函数是
void accept(T t)
```java @Test public void test1 () {
consumo(500, (x) -> System.out.println(x)); }
public void consumo (double money, Consumer
}
<a name="XJlXc"></a>
## Supplier<T> 供给型接口
- `T get();`无参有返回,无中生有
```java
@Test
public void test2 () {
Random ran = new Random();
List<Integer> list = supplier(10, () -> ran.nextInt(10));
for (Integer i : list) {
System.out.println(i);
}
}
/**
* 随机产生 sum 个数量得集合
* @param sum 集合内元素个数
* @param sup
*/
public List<Integer> supplier(int sum, Supplier<Integer> sup){
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < sum; i++) {
list.add(sup.get());
}
return list;
}
Function 函数型接口
R apply(T t)
有参有返回,对来料进行加工然后返回@Test public void test3 () { String s = strOperar(" asdf ", x -> x.substring(0, 2)); System.out.println(s); String s1 = strOperar(" asdf ", x -> x.trim()); System.out.println(s1); } public String strOperar(String str, Function<String, String> fun) { return fun.apply(str); }
Predicate
断言型接口 有参有返回的一种特殊情况,对来料进行判断。
boolean test(T t)
```java @Test public void test4 () { Listl = new ArrayList<>(); l.add(102); l.add(172); l.add(13); l.add(82); l.add(109); List list = filterInt(l, x -> (x > 100)); for (Integer integer : list) { System.out.println(integer);
} }
/**
- 过滤集合
- @param list
- @param pre
- @return
*/
public List
filterInt(List list, Predicate pre){ List l = new ArrayList<>(); for (Integer integer : list) {
} return l; } ```if (pre.test(integer)) { l.add(integer); }