Java Lambda概要
- Java Lambda表达式是一种匿名函数;它没有声明的方法,即没有访问修饰符、返回值声明和名字。
Java Lambda表达式基本语法
- Java中的Lambda表达式基本语法:
- (argument) -> {body}
- 比如说:
- (arg1,arg2) -> {body}
- (type1 arg1,type2 arg2) -> {body}
- arg1 -> {body}
- s -> System.out.println(s)
Java Lambda表达式结构
- 一个Lambda表达式可以有0个或多个参数。
- 参数的类型既可以明确声明,也可以根据上下文来推断。例如,(int a)和(a)效果相同
- 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a,b)或(int a,int b)或(String a,String b,float c)
- 空圆括号代表参数集为空。例如:() -> 42
- 当只有一个参数,且其类型可以推导时,圆括号()可省略。例如:a -> return a * a
- Lambda表达式的主题可以包含0条或多条语句
- 如果Lambda表达式的主题只有一条语句,花括号{}可以省略。匿名函数的返回类型与该主体表达式一致
- 如果Lambda表达式的主体包含一条以上语句,则表达式主体必须包含在花括号{}中(形成代码块),匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空
Java Lambda示例
- Lambda示例说明
- (int a,int b) -> {return a + b;}
- () -> System.out.println("hello world");
- (String s) -> {System.out.println(s);}
- () -> 42
- () -> {return 3.1415};
Lambda表达式作用
- 传递行为,而不仅仅是值
- 提升抽象层次
- API重用性更好
- 更加灵活
方法引用
其实是lambda表达式的一种简化写法。所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名。
本质上可以将方法引用看作是一个“函数指针” ——function pointer。
如下所示:
ObjectReference::methodName
一般方法的引用格式:
- 1、如果是静态方法,则是ClassName::staticmethodName。如 Object ::equals
- 2、如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
- 3、如果是实例方法,则可以ClassName::methodName。如Object ::equals;
- 4、构造函数.则是ClassName::new
方法引用使用场景:lambda表达式只有一行代码,且这行代码调用的这个方法是已经存在的,那么就可以用方法引用去替换掉lambda表达式。
此为方法引用最简单例子:
public class MethodReferenceTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello","world","helloworld");
list.forEach(item -> System.out.println());
list.forEach(System.out::println);
}
}
接下来看一下稍微复杂的例子:
1、如果是静态方法,则是ClassName::staticmethodName。如 Object ::equals
public class Student {
private String name;
private int score;
public Student() {
}
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public static int compareStudentBySocre(Student student1,Student student2){
return student1.getScore() - student2.getScore();
}
public static int compareStudentByName(Student student1,Student student2){
return student1.getName().compareTo(student2.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
list.sort((studentParam1,studentParam2) -> Student.compareStudentBySocre(studentParam1,studentParam2));
list.sort((studentParam1,studentParam2) -> Student.compareStudentByName(studentParam1,studentParam2));
System.out.println(list);
list.sort(Student::compareStudentBySocre);
list.sort(Student::compareStudentByName);
System.out.println(list);
}
}
2、如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
public class StudentComparator {
public int compareStudentBySocre(Student student1,Student student2){
return student1.getScore() - student2.getScore();
}
public int compareStudentByName(Student student1,Student student2){
return student1.getName().compareTo(student2.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
StudentComparator studentComparator = new StudentComparator();
list.sort((studentParam1,studentParam2) -> studentComparator.compareStudentBySocre(studentParam1,studentParam2));
list.sort((studentParam1,studentParam2) -> studentComparator.compareStudentByName(studentParam1,studentParam2));
list.sort(studentComparator::compareStudentBySocre);
list.sort(studentComparator::compareStudentByName);
}
}
3、如果是实例方法,则可以ClassName::methodName。如Object ::equals;
public class Student {
......字段、setter和getter方法省略......
public int compareBySocre(Student student){
return this.getScore() - student.getScore();
}
public int compareByName(Student student){
return this.getName().compareTo(student.getName());
}
}
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",70);
Student student4 = new Student("zhaoliu",60);
List<Student> list = Arrays.asList(student1,student2,student3,student4);
list.sort(Student::compareBySocre);
list.sort(Student::compareByName);
}
}
4、构造函数.则是ClassName::new
public class MethodReferenceTest2 {
public static void main(String[] args) {
List<String> citys = Arrays.asList("shenzhen","shanghai","beijing","chongqing");
Collections.sort(citys,String::compareTo);
MethodReferenceTest2 methodReferenceTest2 = new MethodReferenceTest2();
String test2String = methodReferenceTest2.getString(Student::new);
String string2 = methodReferenceTest2.getString2(" hello ", String::new);
}
public <T> String getString(Supplier<T> supplier){
return supplier.get() + "test";
}
public <T> T getString2(T str, Function<T,T> function){
return function.apply(str);
}
}
可以看出,doSomething方法就是lambda表达式的实现,这样的好处就是,如果你觉得lambda的方法体会很长,影响代码可读性,方法引用就是个解决办法。
函数式接口
函数式接口(functional interface 也叫功能性接口,其实是同一个东西)。简单来说,函数式接口是只包含一个方法的接口。比如Java标准库中的java.lang.Runnable和 java.util.Comparator都是典型的函数式接口。
java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断, 但 最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。
Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现;每个lambda表达式都能隐式的赋值给函数式接口。
关于函数式接口:
- 1、如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口。
- 2、如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。
- 3、如果某个接口只有一个抽象方法,但我们并没有给该接口声明@FunctionalInterface注解,那么编译器依旧会将该接口看做是函数式接口。
高阶函数
如果一个函数接收另一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数。
自定义函数式接口
public class Test3 {
public static void main(String[] args) {
TheInterface i1 = () -> {};
System.out.println(i1.getClass().getInterfaces()[0]);
TheInterface2 i2 = () -> {};
System.out.println(i2.getClass().getInterfaces()[0]);
}
}
@FunctionalInterface
interface TheInterface{
void myMethod();
}
@FunctionalInterface
interface TheInterface2{
void myMethod2();
}
我们知道使用Lambda表达式是需要使用函数式接口的,那么,岂不是在我们开发过程中需要定义许多函数式接口,其实不然,java8其实已经为我们定义好了4类内置函数式接口,这4类接口其实已经可以解决我们开发过程中绝大部分的问题,只有一小部分比较特殊得情况需要我们自己去定义函数式接口,下面就简单来学习一下java8内置得4大核心函数式接口。
一、Consumer<T>:消费型接口(void accept(T t))
Consumer接口:该接口定义了一个void accept(T)的抽象方法,其函数描述符为 (T) -> void,如果你需要一个操作某一对象,但无需返回的的函数式接口,那么就可以使用Consumer接口。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
来看一个简单得例子:
public class Test3 {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello","world","helloworld");
list.forEach(item -> System.out.println(item.toUpperCase()));
List<String> list2 = new ArrayList<>();
list.forEach(item -> list2.add(item.toUpperCase()));
list2.forEach(item -> System.out.println(item));
list.stream().map(item -> item.toUpperCase()).forEach(item -> System.out.println(item));
list.stream().map(String::toUpperCase).forEach(System.out::println);
}
}
以上为消费型接口,有参数,无返回值类型的接口。
二、Supplier<T>:供给型接口(T get())
Supplier接口:既然有消费者接口(Consumer),那就要有生产者接口(Supplier),该接口定义了一个 T get() 的抽象方法,其函数描述符为 () -> T,如果你需要一个从某一对象获取到某值的接口,那么就可以用Supplier。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
来看一个简单得例子:
public class SupplierTest {
public static void main(String[] args) {
Supplier<String> supplier = () -> "hello world";
System.out.println(supplier.get());
Supplier<Student> supplier1 = () -> new Student("张三",20);
System.out.println(supplier1.get().getName());
Supplier<Student> supplier2 = Student::new;
System.out.println(supplier2.get().getName());
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
上面就是一个供给类型得接口,只有产出,没人输入,就是只有返回值,没有入参
三、Function<T, R>:函数型接口(R apply(T t))
Function接口:该接口定义了一个 R applay(T)类型的抽象函数,它接受一个泛型变量T,并返回一个泛型变量R,如果你需要将一个对象T映射成R,那么就可以使用Function接口。例如我们需要打印一个花名册,但是具体打印的格式需要可灵活配置,那就将花名册打印格式参数化,需要使用 (Student) -> String 类型的函数描述符,与Function接口吻合。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
下面看一个简单的例子:
public class FunctionTest {
public static void main(String[] args) {
FunctionTest test = new FunctionTest();
int compute1 = test.compute(1, value -> {return 2 * value;});
System.out.println(compute1);
int compute2 = test.compute(2, value -> 5 + value);
System.out.println(compute2);
int compute3 = test.compute(3, value -> value * value);
System.out.println(compute3);
String compute4 = test.convert(5,value -> String.valueOf(value + "helloworld"));
System.out.println(compute4);
Function<Integer,Integer> function = value -> value * 2;
int compute5 = test.compute(4, function);
System.out.println(compute5);
}
public <T> T compute(T a, Function<T,T> function){
T result = function.apply(a);
return result;
}
public String convert(int a,Function<Integer,String> function){
String result = function.apply(a);
return result;
}
}
下面看一个稍微复杂的例子:
public class FunctionTest2 {
public static void main(String[] args) {
FunctionTest2 test = new FunctionTest2();
int compute = test.compute(2, value -> value * 3, value -> value * value);
int compute2 = test.compute2(2, value -> value * 3, value -> value * value);
System.out.println(compute);
System.out.println(compute2);
}
public <T> T compute(T a, Function<T,T> function1,Function<T,T> function2){
return function1.compose(function2).apply(a);
}
public <T> T compute2(T a,Function<T,T> function1,Function<T,T> function2){
return function1.andThen(function2).apply(a);
}
}
上面就是一个函数型接口,输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致。
四、Predicate<T>:断言型接口(boolean test(T t))
Predicate接口:该接口定义了一个支持泛型的boolean test( T)的抽象方法,其函数描述符为 (T)-> boolean,现在我们就可以直接使用Predicate接口来替代OToBoolean接口了。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
下面看一个简单得例子:
public class PredicateTest {
public static void main(String[] args) {
Predicate<String> predicate = p -> p.length() > 5;
boolean test = predicate.test("hello");
System.out.println(test);
}
}
下面看一个稍微复杂的例子:
public class PredicateTest2 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
conditionFilter(list,item -> item % 2 == 0);
conditionFilter(list,item -> item > 5);
conditionFilter(list,item -> true);
//找出集合中所有大于5且为偶数的元素
conditionFilter2(list,item -> item > 5,item -> item % 2 == 0);
//找出集合中大于5或为偶数的元素
conditionFilter3(list,item -> item > 5,item -> item % 2 == 0);
//找出集合中所有大于5且为偶数的元素基础上取反
conditionFilter4(list,item -> item > 5,item -> item % 2 == 0);
boolean test1 = isEqual("hello").test("hello");
System.out.println(test1);
boolean test2 = isEqual(new Date()).test(new Date());
System.out.println(test2);
}
public static <T> void conditionFilter(List<T> list, Predicate<T> predicate){
list.forEach(t -> {
if(predicate.test(t)){
System.out.println(t);
}
});
}
public static <T> void conditionFilter2(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.and(predicate2).test(item)){
System.out.println(item);
}
});
}
public static <T> void conditionFilter3(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.or(predicate2).test(item)){
System.out.println(item);
}
});
}
public static <T> void conditionFilter4(List<T> list,Predicate<T> predicate1,Predicate<T> predicate2){
list.forEach(item -> {
if(predicate1.and(predicate2).negate().test(item)){
System.out.println(item);
}
});
}
public static <T> Predicate<T> isEqual(T t){
return Predicate.isEqual(t);
}
}
上面就是一个断言型接口,输入一个参数,输出一个boolean类型得返回值。
五、其他的一些重要函数式接口
**BiFunction<T, U, R> **
参数类型有2个,为T,U,返回值为R,其中方法为R apply(T t, U u)
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
下面看一个简单得例子:
public class FunctionTest2 {
public static void main(String[] args) {
FunctionTest2 test = new FunctionTest2();
int compute3 = test.compute3(2, 3, (value1, value2) -> value1 + value2);
System.out.println(compute3);
int compute4 = test.compute4(3, 4, (value1, value2) -> value1 + value2, value -> value * value);
System.out.println(compute4);
}
public <T> T compute3(T a, T b, BiFunction<T,T,T> function){
return function.apply(a,b);
}
public <T> T compute4(T a,T b,BiFunction<T,T,T> biFunction,
Function<T,T> function){
return biFunction.andThen(function).apply(a,b);
}
}
public class PersonTest {
public static void main(String[] args) {
Person person1 = new Person("zhangsan",20);
Person person2 = new Person("lisi",38);
Person person3 = new Person("wangwu",40);
List<Person> list = Arrays.asList(person1,person2,person3);
List<Person> resultList = getPersonByUsername("zhangsan", list);
resultList.forEach(person -> System.out.println(person));
List<Person> personByAge = getPersonByAge(20, list);
personByAge.forEach(person -> System.out.println(person));
List<Person> personByAge2 = getPersonByAge2(20, list, (age, personList) ->
personList.stream().filter(person -> person.getAge() > age).collect(Collectors.toList())
);
personByAge2.forEach(person -> System.out.println(person));
}
public static List<Person> getPersonByUsername(String username,List<Person> list){
return list.stream().filter(person -> person.getName().equals(username)).collect(Collectors.toList());
}
public static List<Person> getPersonByAge(int age,List<Person> list){
/*BiFunction<Integer,List<Person>,List<Person>> biFunction = (ageOfPerson,personList) -> {
return personList.stream().filter(person -> person.getAge() > ageOfPerson).collect(Collectors.toList());
};*/
//这里下面一行代码和上面注释掉的代码一个意思,只是写法更简洁
BiFunction<Integer,List<Person>,List<Person>> biFunction = (ageOfPerson,personList) ->
personList.stream().filter(person -> person.getAge() > ageOfPerson).collect(Collectors.toList());
return biFunction.apply(age,list);
}
public static <T> List<T> getPersonByAge2(int age,List<T> list,BiFunction<Integer,List<T>,List<T>> biFunction){
return biFunction.apply(age,list);
}
}
BinaryOperator<T>(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为T apply(T t1, T t2)
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
下面看一个简单得例子:
public class BinaryOperatorTest {
public static void main(String[] args) {
Integer compute = compute(3, 5, (value1, value2) -> value1 + value2);
System.out.println(compute);
String min1 = getShortMin("hello", "world", (value1, value2) -> value1.compareTo(value2));
System.out.println(min1);
String min2 = getShortMin("hello", "world", (value1, value2) -> value1.charAt(0) - value2.charAt(0));
System.out.println(min2);
String max = getShortMax("hello", "world", (value1, value2) -> value1.charAt(0) - value2.charAt(0));
System.out.println(max);
}
public static <T> T compute(T a, T b, BinaryOperator<T> binaryOperator){
return binaryOperator.apply(a,b);
}
/**
* 返回两个数的较小值
* @param a
* @param b
* @param comparator
* @param <T>
* @return
*/
public static <T> T getShortMin(T a, T b, Comparator<T> comparator){
return BinaryOperator.minBy(comparator).apply(a,b);
}
/**
* 返回两个数的较大值
* @param a
* @param b
* @param comparator
* @param <T>
* @return
*/
public static <T> T getShortMax(T a, T b, Comparator<T> comparator){
return BinaryOperator.maxBy(comparator).apply(a,b);
}
}
Comparator<T>接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
下面看一个简单得例子:
public class StringComparator {
public static void main(String[] args) {
List<String> list = Arrays.asList("zhangsan","wangwu","lisi","zhaoliu");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println(list);
Collections.sort(list,(o1,o2) -> {
return o2.compareTo(o1);
});
System.out.println(list);
//expression o2.compareTo(o1)
//statement {return o2.compareTo(o1);}
Collections.sort(list,(o1,o2) -> o2.compareTo(o1));
System.out.println(list);
Collections.sort(list,Comparator.reverseOrder());
System.out.println(list);
}
}
Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
下面看一个简单得例子:
new Thread(() -> System.out.println("hello world")).start();
除了上述得类型得接口外还有其他的一些接口供我们使用:
1).BiFunction<T, U, R>
参数类型有2个,为T,U,返回值为R,其中方法为R apply(T t, U u)
2).UnaryOperator<T>(Function子接口)
参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为T apply(T t)
3).BinaryOperator<T>(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为T apply(T t1, T t2)
4).BiConsumcr(T, U)
参数为T,U无返回值,其中方法为 void accept(T t, U u)
5).ToIntFunction<T>、ToLongFunction<T>、ToDoubleFunction<T>
参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。
6).IntFunction<R>、LongFunction<R>、DoubleFunction<R>
参数分别为int,long,double,返回值为R。
以上就是java8内置得核心函数式接口,其中包括了大部分得方法类型,所以可以在使用得时候根据不同得使用场景去选择不同得接口使用。
这里的函数式接口可以理解成,定义了很多不同的参数个数待实现接口。
Java8内置了很多函数式接口(在java.util.function包下的接口),下面表格有列出:
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
Function | R apply(T t) | 一个参数 | R |
DoubleFunction | R apply(double value) | 一个参数 | R |
IntFunction | R apply(int value) | 一个参数 | R |
UnaryOperator extends Function | T apply(T t) | 一个参数 | T |
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
BiFunction | R apply(T t, U u) | 两个参数 | R |
BinaryOperator extends BiFunction | T apply(T t, T u) | 两个参数 | T |
DoubleBinaryOperator | double applyAsDouble(double l, double r) | 两个参数 | double |
DoubleBinaryOperator | double applyAsDouble(double l, double r) | 两个参数 | |
double | |||
DoubleUnaryOperator | double applyAsDouble(double operand) | 一个参数 | double |
IntBinaryOperator | int applyAsInt(int left, int right) | 两个参数 | int |
LongBinaryOperator | long applyAsLong(long left, long right) | 两个参数 | long |
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
DoubleToIntFunction | int applyAsInt(double value) | 一个参数 | int |
IntToLongFunction | long applyAsLong(int value) | 一个参数 | long |
DoubleToLongFunction | long applyAsLong(double value) | 一个参数 | long |
IntToDoubleFunction | double applyAsDouble(int value) | 一个参数 | double |
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
Predicate | boolean test(T t) | 一个参数 | boolean |
BiPredicate | boolean test(T t, U u) | 两个参数 | boolean |
DoublePredicate | boolean test(double value) | 一个参数 | boolean |
IntPredicate | boolean test(int value) | 一个参数 | boolean |
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
Supplier | T get() | 无 | T |
BooleanSupplier | boolean getAsBoolean() | 无 | boolean |
DoubleSupplier | double getAsDouble() | 无 | boolean |
IntSupplier | int getAsInt() | 无 | boolean |
接口 | 方法 | 参数 | 返回值 |
---|---|---|---|
Consumer | void accept(T t) | 一个参数 | void |
BiConsumer | void accept(T t, U u) | 两个参数 | void |
DoubleConsumer | void accept(double value) | 一个参数 | void |
IntConsumer | void accept(int value) | 一个参数 | void |
ObjDoubleConsumer | void accept(T t, double value) | 两参数 | void |
上面为Java 8 中函数式接口列表
这里给出一份较为全的函数式接口与描述符对应的接口声明列表:
函数式接口 | 函数描述符 |
---|---|
Predicate | (T) -> boolean |
Consumer | (T) -> void |
Function< T, R > | (T) -> R |
Supplier | () -> T |
UnaryOperator | (T) -> T |
BinaryOperator | (T, T) -> T |
BiPredicate | (L, R) -> boolean |
BiConsumer | (T, U) -> void |
BiFunction | (T, U) -> R |
如果同学们需要的函数式接口没有被覆盖,可以根据JDK中的声明来编写适合自己使用的函数式接口声明。
Optional
用于简化Java中对空值的判断处理,以防止出现各种空指针异常。
Optional实际上是对一个变量进行封装,它包含有一个属性value,实际上就是这个变量的值。
Optional对象创建
它的构造函数都是private类型的,因此要初始化一个Optional的对象无法通过其构造函数进行创建。它提供了一系列的静态方法用于构建Optional对象:
empty
用于创建一个空的Optional对象;其value属性为Null。
如:
Optional o = Optional.empty();
of
根据传入的值构建一个Optional对象;
传入的值必须是非空值,否则如果传入的值为空值,则会抛出空指针异常。
使用:
o = Optional.of("test");
ofNullable
根据传入值构建一个Optional对象
传入的值可以是空值,如果传入的值是空值,则与empty返回的结果是一样的。
方法
Optional包含以下方法:
方法名 | 说明 |
---|---|
get | 获取Value的值,如果Value值是空值,则会抛出NoSuchElementException异常;因此返回的Value值无需再做空值判断,只要没有抛出异常,都会是非空值。 |
isPresent | Value是否为空值的判断; |
ifPresent | 当Value不为空时,执行传入的Consumer; |
ifPresentOrElse | Value不为空时,执行传入的Consumer;否则执行传入的Runnable对象; |
filter | 当Value为空或者传入的Predicate对象调用test(value)返回False时,返回Empty对象;否则返回当前的Optional对象 |
map | 一对一转换:当Value为空时返回Empty对象,否则返回传入的Function执行apply(value)后的结果组装的Optional对象; |
flatMap | 一对多转换:当Value为空时返回Empty对象,否则传入的Function执行apply(value)后返回的结果(其返回结果直接是Optional对象) |
or | 如果Value不为空,则返回当前的Optional对象;否则,返回传入的Supplier生成的Optional对象; |
stream | 如果Value为空,返回Stream对象的Empty值;否则返回 Stream.of(value)的Stream对象; |
orElse | Value不为空则返回Value,否则返回传入的值; |
orElseGet | Value不为空则返回Value,否则返回传入的Supplier生成的值; |
orElseThrow | Value不为空则返回Value,否则抛出Supplier中生成的异常对象; |
使用场景
常用的使用场景如下:
判断结果不为空后使用
如某个函数可能会返回空值,以往的做法:
String s = test();
if (null != s) {
System.out.println(s);
}
现在的写法就可以是:
Optional<String> s = Optional.ofNullable(test());
s.ifPresent(System.out::println);
乍一看代码复杂度上差不多甚至是略有提升;那为什么要这么做呢?
一般情况下,我们在使用某一个函数返回值时,要做的第一步就是去分析这个函数是否会返回空值;如果没有进行分析或者分析的结果出现偏差,导致函数会抛出空值而没有做检测,那么就会相应的抛出空指针异常!
而有了Optional后,在我们不确定时就可以不用去做这个检测了,所有的检测Optional对象都帮忙我们完成,我们要做的就是按上述方式去处理。
变量为空时提供默认值
如要判断某个变量为空时使用提供的值,然后再针对这个变量做某种运算;
以往做法:
if (null == s) {
s = "test";
}
System.out.println(s);
现在的做法:
Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElse("test"));
变量为空时抛出异常,否则使用
以往写法:
if (null == s) {
throw new Exception("test");
}
System.out.println(s);
现在写法:
Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElseThrow(()->new Exception("test")));