一:Lambda表达式
理解:
Lambda表达式相当于代替匿名内部类的,但要求:匿名内部类实现的接口中只有一个抽象方法
应用场景:
Lambda表达式同匿名内部类的应用场景,一般作为接口的实例传递给方法
直接做为接口的实例赋值给接口
注意事项:
①参数类型可以省略
②如果Lambda体中只有一句话,则大括号也可以省略
③如果Lambda体中只有一句话而且是return语句,则return也可以省略
④如果只有一个参数,则小括号也可以省略
@Test
public void test2() {
//匿名内部类
Comparator<String> c1 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
System.out.println("");
return o1.compareTo(o2);
}
};
//Lambda
Comparator<String> c2 = ( o1, o2)-> o1.compareTo(o2);
}
二:函数式接口
常用函数:
- * 消费型接口Consumer
- * 供给型接口Supplier
- * 函数型接口Function
- * 断定型接口Predicate
//测试:消费型接口Consumer
@Test
public void test1() {
Consumer<Integer> con2 = t->{
if (t>1000) {
System.out.println("吃大烤鸭");
}else{
System.out.println("吃肉夹馍");
}
};
con2.accept(2000);
}
//测试供给型接口Supplier
@Test
public void test2() {
Supplier
<String> sup = ()->"john".toUpperCase();
System.out.println(sup.get());
}
//测试函数型接口Function
@Test
public void test3() {
Function
<Double,Double> fun = d->Math.pow(d, 2);
System.out.println(fun.apply(100d));
}
//测试断定型接口Predicate
@Test
public void test4() {
Predicate
<Employee> pre = e->e.getName().contains("a");
System.out.println(pre.test(new Employee("john", 12, 1000, '女')));
三、各类引用
1、方法引用
理解:
满足一定条件的Lambda表达式的代替,也是作为函数式接口的实例出现!
方法引用仅仅是Lambda表达式的语法糖形式,提高语义性和阅读性
要求:
1、Lambda体中只有一句话
2、仅有的这一句话为方法的调用
3、调用的方法中的参数列表和返回 ,与实现的抽象方法的参数列表和返回一致!
如果是类名调用普通方法,则要求:抽象方法的第一次参数为调用方法的调用者,其他参数类型一致!
//测试形式1:对象::普通方法
@Test
public void test1() {
//使用Lambda表达式
Consumer<String> con = s->System.out.println(s);
//使用方法引用
Consumer<String> con2 = System.out::println;
con2.accept("hello");
}
//测试形式2:类::静态方法
@Test
public void test2() {
//使用Lambda表达式
Comparator<Integer> com1 = (i1,i2)->Integer.compare(i1, i2);
Comparator<Double> com3 = (i1,i2)->Double.compare(i1, i2);
//使用方法引用
Comparator<Integer> com2 = Integer::compare;
Comparator<Double> com4 = Double::compare;
}
//测试形式3:类::普通方法
@Test
public void test3() {
//使用匿名内部类
Comparator<String> com1 = new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
//使用Lambda表达式
Comparator<String> com2 = (o1,o2)->o1.compareTo(o2);
//使用方法引用
Comparator<String> com3 = String::compareTo;
}
2、构造器引用
理解:
构造器引用 相当于对满足一定条件的Lambda表达式的简化
条件:
1、Lambda体中仅仅只有一句话
2、Lambda体中仅有的一句话为通过调用构造器创建对象
3、构造器的参数列表和抽象方法的参数列表保持一致。抽象方法的返回类型正好为该对象的类型!
//案例1:String s = new String();
@Test
public void test1() {
//使用匿名内部类
Supplier<String> sup1 = new Supplier<String>(){
@Override
public String get() {
return new String();
}
};
//使用构造器引用
Supplier<String> sup2 = String::new;
}
//案例2:String s = new String("hello");
@Test
public void test2() {
//使用匿名内部类
Function<String,String> fun1 = new Function<String,String>(){
@Override
public String apply(String t) {
return new String(t);
}
};
//使用构造器引用
Function<String,String> fun2 = String::new;
}
//案例3: Employee emp = new Employee(String name, int age, double salary, char sex);
@Test
public void test3() {
//使用匿名内部类
A<String,Integer,Double,Character,Employee> a = new A<String,Integer,Double,Character,Employee>(){
@Override
public Employee method(String t, Integer r, Double m, Character u) {
return new Employee(t,r,m,u);
}
};
//使用构造器引用
A<String,Integer,Double,Character,Employee> b = Employee::new;
}
interface A<T,R,M,U,V>{
V method(T t,R r,M m,U u);
}
3、 数组引用
理解:
数组引用相当于满足一定条件的Lambda表达式的代替,也是作为函数式接口的实例出现
要求:
1、Lambda体中仅仅只有一句话
2、仅有的一句话为创建数组对象
3:抽象方法的参数类型为数组的长度类型,返回类型为创建的数组类型
//案例1:return new String[5];
/*
* 返回类型:String[]
* 参数类型:Integer
*/
@Test
public void test1() {
//使用匿名内部类
Function<Integer,String[]> fun1 = new Function<Integer,String[]>(){
@Override
public String[] apply(Integer t) {
return new String[t];
}
};
//使用数组引用
Function<Integer,String[]> fun2 = String[]::new;
}
//案例2:return new StringBuffer[6];
@Test
public void test2() {
Function<Integer,StringBuffer[]> fun = StringBuffer[]::new;
}
四,Stream API
注意:
1、分为三部进行执行,如果不执行最后的最后一步终止前面则不会执行
2、Stream为“一次性消费”,即创建一次只能是使用一次。
1、开始操作(创建Stream对象指向一个具体的数据源)
此类用于演示Stream的开始操作:
方式一:根据集合获取Stream对象 (数据源:集合)
方式二:根据数组获取Stream对象 (数据源:数组)
方式三:根据一组序列值获取Stream对象(数据源:一组值)
方式四:创建无限流,根据一个规则获取Stream对象(数据源:自定义规则)
//方式一:根据集合获取Stream对象 (数据源:集合) ★
@Test
public void test1() {
List<Employee> list = EmployeeData.getEmployees();
//获取串行流对象
Stream<Employee> stream = list.stream();
//获取并行流对象
Stream<Employee> parallelStream = list.parallelStream();
//终止操作
//使用匿名内部类:
// stream.forEach(new Consumer<Employee>(){
//
// @Override
// public void accept(Employee t) {
// System.out.println(t);
// }
//
// });
//使用Lambda表达式:
// stream.forEach(t->System.out.println(t));
//使用方法引用:
stream.forEach(System.out::println);
}
//方式二:根据数组获取Stream对象 (数据源:数组)
@Test
public void test2() {
String[] arr = {"john","lucy","lily"};
// Stream<String> stream = Arrays.stream(arr);
//
// stream.forEach(System.out::println);
Arrays.stream(arr).forEach(System.out::println);
}
// 方式三:根据一组序列值获取Stream对象(数据源:一组值)
@Test
public void test3() {
Stream<Character> of = Stream.of('a','b','c','d');
of.forEach(System.out::println);
}
//方式四:生成无限流
@Test
public void test4() {
//匿名内部类
// Stream<Double> generate = Stream.generate(new Supplier<Double>(){
//
// @Override
// public Double get() {
// return Math.random();
// }
//
// });
//
//Lambda
// Stream<Double> generate2 = Stream.generate(()->Math.random());
//方法引用
Stream<Double> generate3 = Stream.generate(Math::random);
generate3.forEach(System.out::println);
}
2
、
Stream的中间操作
*中间操作可以形成流水线操作
常见方法:
filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
limit(n)——截断流,使其元素不超过给定数量。
skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
map(Function<元素类型,R>)——映射,根据元素本身一一映射成新的元素
flatMap(Function<元素类型,Stream>)——映射
sorted()——自然排序
sorted(Comparator)——定制排序
List<Employee> list;
@Before
public void before(){
list = EmployeeData.getEmployees();
}
//筛选与切片
@Test
public void test1() {
//1.获取Stream对象
Stream<Employee> stream = list.stream();
//2.中间操作
//filter:根据条件过滤
// Stream<Employee> filter = stream.filter(t->t.getAge()>30);
//limit:用于限制最大元素个数
// Stream<Employee> limit = stream.limit(50);
//skip:跳过指定的个数
// Stream<Employee> skip = stream.skip(3);
//distinct:去重
Stream<Employee> distinct = stream.distinct();
//3.终止操作
distinct.forEach(System.out::println);
}
//测试:映射
@Test
public void test2() {
//1.获取Stream对象
Stream<Employee> stream = list.stream();
//2.中间操作
//map:映射
// Stream<String> map = stream.map(new Function<Employee,String>(){
//
// @Override
// public String apply(Employee t) {
// return t.getName();
// }});
// Stream<String> map = stream.map(Employee::getName);
//flatMap:映射
//使用匿名内部类:
// stream.flatMap(new Function<Employee,Stream<Object>>(){
//
// @Override
// public Stream<Object> apply(Employee t) {
// return TestStreamMiddle.employeeToStream(t);
// }
//
// });
//使用方法引用
Stream<Object> flatMap = stream.map(TestStreamMiddle::employeeToStream);
//3.终止操作
flatMap.forEach(System.out::println);
}
//测试排序
@Test
public void test3() {
//1.获取stream对象
Stream<Employee> stream = list.stream();
//2.中间操作
//sorted():根据元素本身的比较性实现自然排序
// Stream<Employee> sorted = stream.sorted();
//sorted(comparator):根据比较器实现定制排序
//进阶1:使用匿名内部类
// stream.sorted(new Comparator<Employee>(){
//
// @Override
// public int compare(Employee o1, Employee o2) {
// return Double.compare(o2.getSalary(), o1.getSalary());
// }
//
// });
//进阶2:使用Lambda
Stream<Employee> sorted2 = stream.sorted((o1,o2)->Double.compare(o2.getSalary(), o1.getSalary()));
//3.终止操作
sorted2.forEach(System.out::println);
}
//自定义规则实现:将员工转换成Stream类型
public static Stream<Object> employeeToStream(Employee e){
Stream<Object> of = Stream.of(e.getName(),e.getAge(),e.getSalary(),e.getSex());
return of;
}
3、Stream的终止操作
常见方法:
count:统计个数
max(Comparator):求最大值
min(Comparator):求最小值
forEach(Consumer):内部迭代
reduce(BinaryOperator<T>):归约、合并
List<Employee> list;
@Before
public void before(){
list = EmployeeData.getEmployees();
}
//测试:count 统计Stream中的元素个数
@Test
public void test1() {
//1.获取stream对象
Stream<Employee> stream = list.stream();
//2.终止操作
long count = stream.count();
System.out.println(count);
}
//测试:max/min 获取Stream中的最大值或最小值
@Test
public void test2() {
//1.获取stream对象
Stream<Employee> stream = list.stream();
//2.终止操作
System.out.println(min);
}
//测试:forEach 获取Stream中的内部迭代
@Test
public void test3() {
//1.获取stream对象
Stream<Employee> stream = list.stream();
//2.终止操作
stream.forEach(System.out::println);
}
//测试:reduce 归约,合并
@Test
public void test4() {
//1.获取stream对象
Stream<Employee> stream = list.stream();
//2.终止操作
/*
* BinaryOperator:
* T apply(T t1,T t2);
*/
//进阶1:匿名内部类:
// stream.reduce(new BinaryOperator<Employee>(){
//
// @Override
// public Employee apply(Employee t, Employee u) {
// return null;
// }
//
// });
Stream<Double> map = stream.map(e->e.getSalary());
Optional<Double> reduce = map.reduce((t,u)->t+u);
System.out.println(reduce);
}
五:Optional类
主要是为了减少空指针异常