1.Lambda表达式
java8的新特性之一,Lambda 表达式,也可称为闭包。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。但是实质上是类似于“语法糖”,将你包装好的代码有编译器来完成转换,从而使代码更加的简洁,不太推荐经常使用,因为它尽管很简洁,但是难懂,难以调试
语法
lambda 表达式的语法格式如下:
(parameters) -> expression
(parameters) ->{ statements; }
Lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
以下通过一个示例来了解具体用法:
public class Lambda {
public static void main(String[] args) {
Lambda lambda = new Lambda();
MathOperation add = (x, y) -> x + y;
MathOperation sub = (x, y) -> x - y;
MathOperation multi = (x, y) -> x * y;
MathOperation div = (x, y) -> x / y;
System.out.println("加法操作:"+lambda.operate(10, 5, add));
System.out.println("减法操作:"+lambda.operate(10, 5, sub));
System.out.println("乘法操作:"+lambda.operate(10, 5, multi));
System.out.println("除法操作:"+lambda.operate(10, 5, div));
}
interface MathOperation{
int operation(int a, int b);
}
private int operate(int a, int b, MathOperation mathoperation){
return mathoperation.operation(a, b);
}
}
输出如下:
加法操作:15
减法操作:5
乘法操作:50
除法操作:2
定义另一个MathOperation接口来实现加减乘除,operation实现接口内的方法。
MathOperation add = (x, y) -> x + y;语句的本质就是:
int add(int a, inb b){
return a + b;
}
MathOperation add用来接收其返回值。
变量作用域
lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
2.方法引用
方法引用和方法的Lambda表达式一样,只不过是操作符不同而已,方法引用使用一对冒号 ::
以下是示例:
Person.java文件
import java.time.LocalDate;
public class Person {
LocalDate birthday;
public static int compareByAge(Person a,Person b){
return a.birthday.compareTo(b.birthday);
}
}
Main.java文件:
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
Person[] peoples = new Person[3];
peoples[0] = new Person();
peoples[1] = new Person();
peoples[2] = new Person();
peoples[0].birthday = LocalDate.of(2019,5,14);
peoples[1].birthday = LocalDate.parse("2019-04-25");
peoples[2].birthday = LocalDate.parse("2019-04-16");
//使用匿名内部类
Arrays.sort(peoples, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.birthday.compareTo(o2.birthday);
}
});
//使用Lambda表达式
Arrays.sort(peoples, (o1, o2) -> o1.birthday.compareTo(o2.birthday));
//使用Lambda表达式和类的静态方法
Arrays.sort(peoples, ((o1, o2) -> Person.compareByAge(o1, o2)));
//使用方法引用(引用类的静态方法
Arrays.sort(peoples, Person::compareByAge);
for (Person p:peoples){
System.out.print(p.birthday+"\t");
}
}
}
在Main.java中 使用了4钟不同的方法来对peoples中的每个person根据日期来排序
3.函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
例如自定义的函数式接口:
public class test {
//通过注解@FunctionalInterface来声明一个函数式接口
@FunctionalInterface
interface GreetingService
{
//只能有一个抽象方法
//但是equals式父类的非抽象方法
boolean equals(Object object);
void sayMessage(String message);
//也可以定义默认的实现方法
default void example(){
}
}
public static void main(String[] args){
//可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
GreetingService greetService = message -> System.out.println("Hello " + message);
greetService.sayMessage("world");
}
}
以下是已有的函数式接口:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
- java.util.function(java1.8新增)
以function里的Predicate 接口(接受一个输入参数 T,返回一个布尔值结果)为示例:
Predicate源码中提供了5个方法
- boolean test(T t);
- default Predicate and(Predicate<? super T> other)
- default Predicate negate()
- default Predicate or (Predicate<? super T> other)
- static Predicate isEqual (Object targetRef)
以下对test(T t)方法进行使用
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Function_interface{
public static void main(String args[]){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// Predicate<Integer> predicate = n -> true
// n 是一个参数传递到 Predicate 接口的 test 方法
// n 如果存在则 test 方法返回 true
System.out.println("输出所有数据:");
// 传递参数 n
eval(list, n->true);
System.out.println();
// Predicate<Integer> predicate1 = n -> n%2 == 0
// n 是一个参数传递到 Predicate 接口的 test 方法
// 如果 n%2 为 0 test 方法返回 true
System.out.println("输出所有偶数:");
eval(list, n-> n%2 == 0 );
System.out.println();
System.out.println("输出大于 3 的所有数字:");
//详细的调用过程
eval(list, new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
if(integer > 3){
return true;
}else {
return false;
}
}
});
System.out.println();
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer i: list) {
if(predicate.test(i)) {
System.out.print(i + "\t");
}
}
}
}
输出如下:
输出所有数据:
1 2 3 4 5 6 7 8 9
输出所有偶数:
2 4 6 8
输出大于 3 的所有数字:
4 5 6 7 8 9
4.默认方法
在函数式接口中已经体现,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个 default 关键字即可实现默认方法。
如自定义的函数式接口中,default便是默认方法
@FunctionalInterface
interface GreetingService
{
//只能有一个抽象方法
//但是equals式父类的非抽象方法
boolean equals(Object object);
void sayMessage(String message);
//也可以定义默认的实现方法
default void example(){
}
}
5.Stream
Stream:(流)是一个来自数据源的元素队列并支持聚合操作
该Api中涉及的方法过多,所以通过示例来了解部分方法的使用
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class Stream {
public static void main(String args[]){
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
System.out.println("列表: " +strings);
//构造stream,然后返回相匹配的stream,再计算stream元素数目
long count = strings.stream().filter(String::isEmpty).count();
System.out.println("空字符串数量为: " + count);
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("字符串长度为 3 的数量为: " + count);
//filter返回筛选不为空元素后的stream
List<String> filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选后的列表: " + filtered);
String mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
//map方法返回映射后的值
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
System.out.println("Squares List: " + squaresList);
List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
System.out.println("列表: " +integers);
//此处mapToint返回Interger类型的stream
//IntSummaryStatistics用于收集统计数据(如计数,最小值,最大值,总和和平均值)的状态对象。
//summaryStatistics()将stream转换为IntSummaryStatistics
IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
System.out.println("随机数: ");
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
// 并行处理
count = strings.parallelStream().filter(String::isEmpty).count();
System.out.println("空字符串的数量为: " + count);
}
}
对于Stream中
- filter()
Stream filter(Predicate<? super T> predicate);
使用到了Predicate该函数接口,因而可用boolean判断(见函数式接口)
- collect()
<R, A> R collect(Collector<? super T, A, R> collector);
用于实现归约操作,可用于集合的转换返回列表,collect(Collectors.toList())