1.概述45
只有一个抽象方法的接口我们称之为函数接口。
JDK的函数式接口都加上了**@FunctionalInterface**注解进行标识。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。
2.常见函数式接口2.1Consumer消费接口46根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。
2.2Function计算转换接口46根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回
2.3Predicate判断接口46根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果
2.4Supplier生产型接口46根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回
3.常用的默认方法473.1and47我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件
例如:打印作家中年龄大于17并且姓名的长度大于1的作家。
StreamDemo// and 打印作家中年龄大于17并且姓名的长度大于1的作家。 47 private static void testAnd() { List<Author> authors = getAuthors(); authors.stream() .filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.and(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getName().length()>1; } })).forEach(author -> System.out.println(author.getAge()+":::"+author.getName())); }
使用lambda表达式写法
authors.stream() .filter(author -> author.getAge()>17&&author.getName().length()>1) .forEach(author -> System.out.println(author.getAge()+":::"+author.getName()));;
3.2or我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用||来拼接两个判断条件。
例如:打印作家中年龄大于17或者姓名的长度小于2的作家。
StreamDemo//or 打印作家中年龄大于17或者姓名的长度小于2的作家。 47 private static void testOr() { List<Author> authors = getAuthors(); authors.stream() .filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.or(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getName().length()<2; } })).forEach(author -> System.out.println(author.getName())); }
3.3negate47Predicate接口中的方法。negate方法相当于是在判断添加前面加了个!表示取反
例如:打印作家中年龄不大于17的作家。
//negate 打印作家中年龄不大于17的作家。 47 private static void tesNegate() { List<Author> authors = getAuthors(); authors.stream() .filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.negate()).forEach(author -> System.out.println(author.getAge())); }
4.方法引用48我们在使用lambda时,如果方法体中只有一个方法的调用的话(包括构造方法),我们可以用方法引用进一步简化代码。
4.1推荐用法48我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们只需要在写完lambda方法发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方法引用即可。
当我们方法引用使用的多了慢慢的也可以直接写出方法引用。
4.2基本格式48类名或者对象名::方法名
4.3语法详解(了解)494.3.1引用类的静态方法49其实就是引用类的静态方法
格式类名::方法名
使用前提如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。
例如:如下代码就可以用方法引用进行简化
StreamDemo
//方法引用 引用类的静态方法 49 private static void test27() { List<Author> authors = getAuthors(); Stream<Author> authorStream = authors.stream(); //匿名内部类写法 /*authorStream.map(new Function<Author, Integer>() { @Override public Integer apply(Author author) { return author.getAge(); } }) .map(new Function<Integer, String>() { @Override public String apply(Integer age) { return String.valueOf(age); } });*/ //lambda表达式 /*authorStream.map(author -> author.getAge()) .map(age -> String.valueOf(age));*/ }
注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。
优化后如下:
StreamDemo
//方法引用 引用类的静态方法 49 private static void test27() { List<Author> authors = getAuthors(); Stream<Author> authorStream = authors.stream(); authorStream.map(author -> author.getAge()) .map(String::valueOf); }
4.3.2引用对象的实例方法50格式对象名::方法名
使用前提如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法
例如://方法引用 引用对象的实例方法 50 private static void test28() { List<Author> authors = getAuthors(); Stream<Author> authorStream = authors.stream(); StringBuilder sb = new StringBuilder(); //匿名内部类 /* authorStream.map(new Function<Author, String>() { @Override public String apply(Author author) { return author.getName(); } }) .forEach(new Consumer<String>() { @Override public void accept(String name) { sb.append(name); } });*/ //lambda表达式 /*authorStream.map(author -> author.getName()) .forEach(name -> sb.append(name));*/ }
优化后:
//方法引用 authorStream.map(author -> author.getName()) .forEach(sb::append);
4.3.3引用类的实例方法51格式类名::方法名
使用前提如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。
例如:MethodDemo
package com.sangeng;//方法引用 引用类的实例方法 51public class MethodDemo { interface UseString{ String use(String str,int start,int length); } public static String subAuthorName(String str, UseString useString){ int start = 0; int length = 1; return useString.use(str,start,length); } public static void main(String[] args) { //匿名内部类 /*subAuthorName("三更草堂", new UseString() { @Override public String use(String str, int start, int length) { return str.substring(start,length); } });*/ }}
优化后
package com.sangeng;//方法引用 引用类的实例方法 51public class MethodDemo { interface UseString{ String use(String str,int start,int length); } public static String subAuthorName(String str, UseString useString){ int start = 0; int length = 1; return useString.use(str,start,length); } public static void main(String[] args) { //方法引用 subAuthorName("三更草堂", String::substring); }}
4.3.4构造器引用52如果方法体中的一行代码是构造器的话就可以使用构造器引用。
格式类名::new
使用前提如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。
例如:StreamDemo
//方法引用 构造器引用 52 private static void test29() { List<Author> authors = getAuthors(); /*authors.stream() .map(author -> author.getName()) .map(name->new StringBuilder(name)) .map(sb->sb.append("-三更").toString()) .forEach(str-> System.out.println(str));*/ }
优化后
//方法引用 authors.stream() .map(author -> author.getName()) .map(StringBuilder::new) .map(sb->sb.append("-三更").()) .forEach(str-> System.out.println(str));