lambda - Stream
一、lambda写法
public class LambdaDemo1{
// 定义接口
interface Printer{
void printer(String val);
}
// 定义一个打印方方法
public void printSomething(String something,Printer printer){
printer.printer(something);
}
public static void main(String[] args){
LambdaDemo1 lambdaDemo1 = new LambdaDemo1();
String something = "something";
// 传统写法
Printer printer = new Printer(){
@Override
public void printer(String val){
System.out.println("传统写法:"val);
}
};
printSomething(something,printer);
// lambda表达式 - 写法1
// lambda表达式用 -> 连接参数和方法体
// (String val) 参数 -- 左侧
// {} 方法体 -- 右侧
Printer printer = (String val) -> {
System.out.println("传统写法:"val);
};
printSomething(something,printer);
// lambda表达式 - 写法2
// 简写“写法1” -- 省略参数类型。
// lambda可根据定义的接口和上下文自动识别参数的类型
// 如果参数与类型不匹配会报错
Printer printer = (val) -> {
System.out.println("传统写法:"val);
};
printSomething(something,printer);
// lambda表达式 - 写法3
// 简写“写法2”
// 省略参数小括号:
// 如果只有一个参数,可省略参数外层的()
// 省略方法体花括号
// 如果方法体中只有一行代码,可省略方法体的{}
Printer printer = val -> System.out.println("传统写法:"val);
printSomething(something,printer);
// lambda表达式 - 写法4
// 简写“写法3”
// printSomething中的参数printer
// Printer printer = val -> System.out.println("传统写法:"val)
printSomething(something,val -> System.out.println("传统写法:"val));
}
}
二、Stream
1、Stream源操作
// 1、集合转Stream
List<String> nameStrs = Arrays.asList("Monkey","Lion","Giraffe","Lemur");
List<String> sorted = nameStrs.stream() //
.filter(s -> s.startsWith("L")) // 过滤。判断条件:以字母"L"开头
.map(String::toUpperCase) // 将过滤到的元素,全部变成大写
.sorted() // 排序
.collect(toList()); // 组合成一个集合
// 2、数组转Stream
String[] players = {"kobe","james","curry","cyyt"};
Stream.of(players)
.filter(s -> s.startsWith("L"))
.map(String::toUpperCase)
.sorted()
.collect(toList());
// 3、HashSet转Stream
String[] players = {"kobe","james","curry","cyyt"};
Set<String> set = new HashSet<>(players);
List<String> sorted = set.stream() //
.filter(s -> s.startsWith("L")) // 过滤。判断条件:以字母"L"开头
.map(String::toUpperCase) // 将过滤到的元素,全部变成大写
.sorted() // 排序
.collect(toList()); // 组合成一个集合
// 4、行文本文件转Stream
Files.lines(Paths.get("file.txt"))
.filter(s -> s.startsWith("L")) // 过滤。判断条件:以字母"L"开头
.map(String::toUpperCase) // 将过滤到的元素,全部变成大写
.sorted() // 排序
.collect(toList()); // 组合成一个集合
2、Stream中间操作
2.1 无状态操作
2.1.1、filter(过滤数据)
public class Employee {
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
// 省略get set 构造
}
public class StreamFilterPredicate {
public static void main(String[] args){
Employee e1 = new Employee(1,20,"男","First1","Last1");
Employee e2 = new Employee(2,21,"女","First2","Last2");
Employee e3 = new Employee(3,24,"男","First3","Last3");
Employee e4 = new Employee(4,22,"男","First4","Last4");
Employee e5 = new Employee(5,21,"女","First5","Last5");
Employee e6 = new Employee(6,25,"男","First6","Last6");
Employee e7 = new Employee(7,23,"女","First7","Last7");
Employee e8 = new Employee(8,25,"男","First8","Last8");
Employee e9 = new Employee(9,26,"女","First9","Last9");
Employee e10 = new Employee(10,21,"男","First10","Last10");
List<Employee> employees = Arrays.asList(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10);
List<Employee> list = employees.stream()
// Predicate 谓语
// e.getAge() > 22 && e.getGender().equals("女") 谓词逻辑
.filter(e -> {e.getAge() > 22 && e.getGender().equals("女")})
.collect(Collectors.toList());
System.out.println(list);
}
}
谓词逻辑也可抽出来,复用
public class Employee {
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
// 省略get set 构造
public static Predicate<Employee> ageGreaterThan22 = x -> x.getAge() > 22;
public static Predicate<Employee> genderWoman = x -> x.getGender().equals("女");
}
public class StreamFilterPredicate {
public static void main(String[] args){
Employee e1 = new Employee(1,20,"男","First1","Last1");
Employee e2 = new Employee(2,21,"女","First2","Last2");
Employee e3 = new Employee(3,24,"男","First3","Last3");
Employee e4 = new Employee(4,22,"男","First4","Last4");
Employee e5 = new Employee(5,21,"女","First5","Last5");
Employee e6 = new Employee(6,25,"男","First6","Last6");
Employee e7 = new Employee(7,23,"女","First7","Last7");
Employee e8 = new Employee(8,25,"男","First8","Last8");
Employee e9 = new Employee(9,26,"女","First9","Last9");
Employee e10 = new Employee(10,21,"男","First10","Last10");
List<Employee> employees = Arrays.asList(e1,e2,e3,e4,e5,e6,e7,e8,e9,e10);
List<Employee> list = employees.stream()
// 支持
// .and():并且
// .or():或者
// .negate():取反
.filter(Employee.ageGreaterThan22.and(Employee.genderWoman).negate())
.collect(Collectors.toList());
System.out.println(list);
}
}
2.1.2、map(转换数据)
- 处理字符串类型集合元素
public class StreamMap1 {
public static void main(String[] args){
List<String> alpha = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");
//不使用Stream管道流
List<String> alphaUpper = new ArrayList<>();
for (String s : alpha) {
alphaUpper.add(s.toUpperCase());
}
System.out.println(alphaUpper); //[MONKEY, LION, GIRAFFE, LEMUR]
// 使用Stream管道流
List<String> collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList());
// "方法引用":String::toUpperCase。效果和s -> s.toUpperCase()效果一样
//List<String> collect = alpha.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
System.out.println(collect); //[MONKEY, LION, GIRAFFE, LEMUR]
}
}
- 处理非字符串类型集合元素
// map()函数不仅可以处理数据,还可以转换数据的类型。如下:
Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.mapToInt(String::length)
.forEach(System.out::println);
// 结果:
// 6
// 4
// 7
// 5
除了mapToInt。还有maoToLong,mapToDouble等等用法。
- 处理对象数据格式转换
public class Employee {
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
// 省略get set 构造
}
public class StreamMap2 {
public static void main(String[] args){
Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");
List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
// 将每一个Employee的年龄增加一岁
// 将性别中的“M”换成“male”,F换成Female。
List<Employee> maped = employees.stream()
.map(e -> {
e.setAge(e.getAge() + 1);
e.setGender(e.getGender().equals("M")?"male":"female");
return e;
}).collect(Collectors.toList());
List<Employee> peeked = employees.stream()
.peek(e -> {
e.setAge(e.getAge() + 1);
e.setGender(e.getGender().equals("M")?"male":"female");
}).collect(Collectors.toList());
// .map()会return回一个新对象
// .peek()是特殊的map函数。对同一个对象操作。实现效果一样。
System.out.println(maped);
System.out.println(peeked);
}
}
2.1.3、flatMap(map展开)
// map可以对管道流中的数据进行转换操作,但是如果管道中还有管道,数组中还有数组该如何处理?
// 即:如何处理二维数组及二维集合类。
// 实现一个简单的需求:
// 将“hello”,“world”两个字符串组成的集合,元素的每一个字母打印出来。
// 如果不用Stream我们怎么写?写2层for循环,第一层遍历字符串,并且将字符串拆分成char数组,第二层for循环遍历char数组。
public class StreamFlatMap {
public static void main(String[] args){
List<String> words = Arrays.asList("hello", "word");
// .map():输出结果为:
// java.util.stream.ReferencePipeline$Head@3551a94
// java.util.stream.ReferencePipeline$Head@531be3c5
// 证明:
// 用map方法是做不到的,这个需求用map方法无法实现。
// map只能针对一维数组进行操作,数组里面还有数组,管道里面还有管道,它是处理不了每一个元素的。
words.stream()
.map(w -> Arrays.stream(w.split("")))
.forEach(System.out::println);
// .flatMap():输出结果为:
// h
// e
// l
// l
// o
// w
// o
// r
// d
// flatMap可以理解为将若干个子管道中的数据全都,平面展开到父管道中进行处理。
words.stream()
.flatMap(w -> Arrays.stream(w.split("")))
.forEach(System.out::println);
}
}
2.2、有状态操作
2.2.1、distinct(去重)
// distinct方法时,调用Object的equals方法进行对象的比较。
// 如果你有自己的比较规则,可以重写equals方法。
// 经过管道处理之后的数据是: ["Monkey", "Lion", "Giraffe", "Lemur"]
List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.distinct()
.collect(Collectors.toList());
2.2.2、limit(取前N个)
// limt方法传入一个整数n,用于截取管道中的前n个元素。
// 经过管道处理之后的数据是:[Monkey, Lion]。
List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.limit(2)
.collect(Collectors.toList());
2.2.3、skip(跳过前N个)
// skip方法与limit方法的使用相反,用于跳过前n个元素,截取从n到末尾的元素。
// 经过管道处理之后的数据是: [Giraffe, Lemur]
List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.skip(2)
.collect(Collectors.toList());
2.2.4、sorted(排序)
-
基本使用
// 默认的情况下,sorted是按照字母的自然顺序进行排序。 // 如下代码的排序结果是:[Giraffe, Lemur, Lion, Monkey] // 字数按顺序G在L前面,L在M前面。第一位无法区分顺序,就比较第二位字母。 List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur") .sorted() .collect(Collectors.toList());
-
像使用sql一样排序集合
-
排序器
// java8以前 Collections.sort(); // java8以后 List<T> list = Arrays.asList(); // Comparator<T> 排序器 list.sort(Comparator<T>); // JDK默认定义的排序规则 // 例如: // 大小写不敏感 list.sort(String.CASE_INSENSITIVE_ORDER); // 自然顺序 list.sort(Comparator.naturalOrder());
-
对象排序
public class Employee { private Integer id; private Integer age; private String gender; private String firstName; private String lastName; // 省略get set 构造 toString() } public class SortList { public static void main(String[] args){ Employee e1 = new Employee(1,23,"M","Rick","Beethovan"); Employee e2 = new Employee(2,13,"F","Martina","Hengis"); Employee e3 = new Employee(3,43,"M","Ricky","Martin"); Employee e4 = new Employee(4,26,"M","Jon","Lowman"); Employee e5 = new Employee(5,19,"F","Cristine","Maria"); Employee e6 = new Employee(6,15,"M","David","Feezor"); Employee e7 = new Employee(7,68,"F","Melissa","Roy"); Employee e8 = new Employee(8,79,"M","Alex","Gussin"); Employee e9 = new Employee(9,15,"F","Neetu","Singh"); Employee e10 = new Employee(10,45,"M","Naveen","Jain"); List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); // 先是按性别的倒序排序,再按照年龄的倒序排序 employees.sort( Comparator.comparing(Employee::getGender) .thenComparing(Employee::getAge) .reversed() ); // 打印 employees.forEach(System.out::println); // 与sql的区别: // 都是正序 ,不加reversed // 都是倒序,最后面加一个reserved // 先是倒序(加reserved),然后正序 // 先是正序(加reserved,负负得正),然后倒序(加reserved) } }
-
3、Stream终端操作
1、ForEach和ForEachOrdered
// 如果我们只是希望将Stream管道流的处理结果打印出来,而不是进行类型转换。
// 我们就可以使用forEach()方法或forEachOrdered()方法。
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.parallel()
.forEach(System.out::println);
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.parallel()
.forEachOrdered(System.out::println); // 按顺序输出
- parallel()函数表示对管道中的元素进行并行处理,而不是串行处理,这样处理速度更快。
- 无法保证顺序: 可能导致管道流中后面的元素先处理,前面的元素后处理。
- forEachOrdered
- 虽然在数据处理顺序上可能无法保障,但是forEachOrdered方法可以在元素输出的顺序上保证与元素进入管道流的顺序一致。
2、collect(元素的收集)
2.1、收集为Set
// 通过Collectors.toSet()方法收集Stream的处理结果,将所有元素收集到Set集合中。
Set<String> collectToSet = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.toSet());
// 最终collectToSet 中的元素是:[Monkey, Lion, Giraffe, Lemur],注意Set会去重。
2.2、收集到List
// 同样,可以将元素收集到List使用toList()收集器中。
List<String> collectToList = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toList());
// 最终collectToList中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
3.3、通用的收集方式
// 可以将数据元素收集到任意的Collection类型:即向所需Collection类型提供构造函数的方式。
LinkedList<String> collectToCollection = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toCollection(LinkedList::new));
//最终collectToCollection中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
// 注意:以上代码中使用了LinkedList::new,实际是调用LinkedList的构造函数,将元素收集到Linked List。
// 当然你还可以使用诸如LinkedHashSet::new和PriorityQueue::new将数据元素收集为其他的集合类型,这样就比较通用了。
3.4、收集到Array
// 通过toArray(String[]::new)方法收集Stream的处理结果,将所有元素收集到字符串数组中。
String[] toArray = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) .toArray(String[]::new);
//最终toArray字符串数组中的元素是: [Monkey, Lion, Giraffe, Lemur, Lion]
3.5、收集到Map
// Function.identity()方法,该方法很简单就是返回一个“ t -> t ”(输入就是输出的lambda表达式)
// distinct()来确保Map键值的唯一性
Map<String, Integer> toMap = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.distinct()
.collect(Collectors.toMap(
Function.identity(), // 元素输入就是输出,作为key
s -> (int) s.chars().distinct().count()// 元素的长度,作为value
));
// 最终toMap的结果是: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}
3.6、groupingBy(分组收集)
Map<Character, List<String>> groupingByList = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
s -> s.charAt(0) , // 根据元素首字母分组,相同的在一组
// counting() // 加上这一行代码可以实现分组统计
));
// 最终groupingByList内的元素: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
//如果加上counting() ,结果是: {G=1, L=3, M=1}
// 这是以上代码过程的说明:groupingBy第一个参数作为分组条件,第二个参数是子收集器。
3.7、其他常用方法
// 判断管道中是否包含2,结果是: true
boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
// 统计元素个数:4
long nrOfAnimals = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur"
).count();
// 管道中元素数据累加结果:sum: 6
int sum = IntStream.of(1, 2, 3).sum();
//管道中元素数据平均值:average: OptionalDouble[2.0]
OptionalDouble average = IntStream.of(1, 2, 3).average();
//管道中元素数据最大值:max: 3
int max = IntStream.of(1, 2, 3).max().orElse(0);
// 全面的统计结果statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
4、Stream查找与匹配元素
4.1、anyMatch
public class Employee {
private Integer id;
private Integer age;
private String gender;
private String firstName;
private String lastName;
// 省略get set 构造 toString()
}
public class MatchFind {
public static void main(String[] args){
Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");
List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
// 查找员工列表中是否包含年龄大于70的员工
// 传统写法
boolean isExistAgeThan70 = false;
for(Employee employee:employees){
if(employee.getAge() > 70){
isExistAgeThan70 = true;
break;
}
}
System.out.println(isExistAgeThan70);
// lambda写法
// .anyMatch():判断Stream流中是否包含某一个“匹配规则”的元素
// 只要包含一个“匹配规则”的元素,就返回true
isExistAgeThan70 = employees.steam().anyMatch(e -> e.getAge() > 70);
}
}
4.2、allMatch
// .allMatch():判断是够Stream流中的所有元素都符合某一个"匹配规则"
// 所有元素都符合某一个"匹配规则",才返回true
boolean isExistAgeThan10 = employees.stream().allMatch(e -> e.getAge() > 10);
4.3、noneMatch
// 判断是否Stream流中的所有元素都不符合某一个"匹配规则"
// 所有元素都不符合某一个"匹配规则",才返回true
boolean isExistAgeLess18 = employees.stream().noneMatch(e -> e.getAge() < 18);
4.4、Optional
// findFirst用于查找第一个符合“匹配规则”的元素,返回值为Optional
// findAny用于查找任意一个符合“匹配规则”的元素,返回值为Optional
// 从列表中按照顺序查找第一个年龄大于40的员工。
Optional<Employee> employeeOptional
= employees.stream().filter(e -> e.getAge() > 40).findFirst();
System.out.println(employeeOptional.get());
// Optional类代表一个值存在或者不存在。在java8中引入,这样就不用返回null了。
// 如果存在,调用get()方法获取。
// 如果不存在,调用get()方法,抛出异常。
-
get()。如果存在,获取值。如果不存在,抛出异常。
-
isPresent() 方法。存在返回true,不存在返回false
boolean is = employees.stream().filter(e -> e.getAge() > 40).findFirst().isPresent(); System.out.println(is);
-
ifPresent(Consumer block)。会在值存在的时候执行给定的代码块。
employees.stream().filter(e -> e.getAge() > 40).findFirst().ifPresent(e -> System.out.println(e));
-
orElse。如果不存在值,给一个默认值
employees.stream().filter(e -> e.getAge() > 40).findFirst() .orElse(new Employee(0,0,"F","",""));
5、Stream集合元素归约
Stream.reduce
,用来实现集合元素的归约.
reduce函数有三个参数:
- Identity标识:一个元素,它是归约操作的初始值,如果流为空,则为默认结果。
- Accumulator累加器:具有两个参数的函数:归约运算的部分结果和流的下一个元素。
- 阶段累加结果作为累加器的第一个参数
- 集合遍历元素作为累加器的第二个参数
- Combiner合并器(可选):当归约并行化时,或当累加器参数的类型与累加器实现的类型不匹配时,用于合并归约操作的部分结果的函数。
5.1、Integer类型规约
// reduce初始值为0,累加器可以是lambda表达式,也可以是方法引用。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer total = numbers
.stream()
.reduce(0, (subtotal, element) -> subtotal + element);
System.out.println(total); //21
Integer result = numbers
.stream()
.reduce(0, Integer::sum);
System.out.println(result); //21
5.2、String类型归约
// 不仅可以归约Integer类型,只要累加器参数类型能够匹配,可以对任何类型的集合进行归约计算。
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String res = letters
.stream()
.reduce("", (partialString, element) -> partialString + element);
System.out.println(res); // abcde
String result = letters
.stream()
.reduce("", String::concat);
System.out.println(result); // abcde
5.3、复杂对象归约
Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");
List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
// 计算每个员工的年龄之和
Integer total = employees.stream()
// 先用map将Stream流中的元素由Employee类型处理为Integer类型(age)。
.map(Employee::getAge)
// 然后对Stream流中的Integer类型进行归约
.reduce(0,Integer::sum);
System.out.println(total); //346
5.4、Combiner合并器的使用
// 在进行并行流计算的时候,可能会将集合元素分成多个组计算。
// 为了更快的将分组计算结果累加,可以使用合并器。
Integer total2 = employees
// 并行流
.parallelStream()
// 获取每个员工年龄
.map(Employee::getAge)
// 对Stream流中的Integer类型进行归约
.reduce(0,Integer::sum,Integer::sum); //注意这里reduce方法有三个参数
System.out.println(total); //346
// 因为Stream流中的元素是Employee,累加器的返回值是Integer,所以二者的类型不匹配。
// 这种情况下可以使用Combiner合并器对累加器的结果进行二次归约,相当于做了类型转换。
Integer total3 = employees.stream()
.reduce(0,(totalAge,emp) -> totalAge + emp.getAge(),Integer::sum); //注意这里reduce方法有三个参数
System.out.println(total); //346
三、函数式接口
1、特点
- 接口有且仅有一个抽象方法
- 允许定义静态非抽象方法
- 允许定义默认defalut非抽象方法(default方法也是java8才有的)
- 在java8之前,如果一个接口存在多个实现类。如果接口中添加新方法,实现类都要去修改一遍,继承该方法。
- 在java8中,用defalut关键字定义一个方法,其接口的实现类就不需要继承该方法,使用时调用即可。
- defalut关键字,还可以在函数式接口中定义非抽象方法,既有方法体。
- 允许java.lang.Object中的public方法
- @FunctionInterface注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。
- 加上该注解能够更好地让编译器进行检查。
- 如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
2、自定义Comparator排序
// 传统写法
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee em1, Employee em2) {
if(em1.getAge() == em2.getAge()){
return 0;
}
return em1.getAge() - em2.getAge() > 0 ? -1:1;
}
});
employees.forEach(System.out::println);
// lambda写法
employees.sort((em1,em2) -> {
if(em1.getAge() == em2.getAge()){
return 0;
}
return em1.getAge() - em2.getAge() > 0 ? -1:1;
});
employees.forEach(System.out::println);
本篇文章学习自 字母哥-《恕我直言:你可能真的不会JAVA系列》。
-
视频地址:
-
博客地址:
-
资料整理: