Java8新特性学习
1、lambda表达式
Lambda允许将函数作为参数传递到方法中,可以使代码变得更加紧凑
使用lambda可以对某些接口进行简单的实现,不过不是所有接口都可以使用lambda来实现
Lambda规定接口中只能有一个需要被实现的方法(不是说接口中只能有一个方法)
Java8中被default修饰的方法会有默认实现,不是必须被实现的方法,这样不影响lambda的使用
语法形式是:()-> {} ,()是参数列表,{}是描述方法体
简单的lambda实现:
public class Java8Tester {
public static void main(String args[]){
// 不用括号
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
GreetingService greetingService = new GreetingService() {
@Override
public void sayMessage(String message) {
System.out.println("Hello " + message);
}
};
greetService1.sayMessage("Runoob");
greetingService.sayMessage("Baidu");
}
interface GreetingService {
void sayMessage(String message);
}
}
我们可以把上面的lambda看成下面的匿名内部类的实现方法
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
意思是实现GreetingService的接口方法,其中message是参数,方法体是 System.out.println("Hello " + message);
故可以通过greetService1.sayMessage(“Runoob”);直接调用
-
可以直接省略参数类型,编译器自动识别参数
(int a,int b) --> (a,b)
-
如果只有一个参数可以不加(),多个需要加
(int a) --> a
-
方法体中只有一个语句,可以省略{}
{System.out.println("Hello " + message);} --> System.out.println("Hello " + message);
-
方法体中只有一个表达式返回值,编译器会自动返回值,大括号需要指定明表达式返回了一个数值
lambda表达式只能访问标记了final的外部变量,或者是局部变量但是该变量后面必须不能被修改(具有隐式的final属性)
public class Java8Tester {
final static String FINAL_1 = "1";
public static void main(String args[]){
final String FINAL_2 = "2";
// 不用括号
String final_3 = "3";
GreetingService greetService1 = message -> System.out.println("Hello " + message + FINAL_1 + FINAL_2 + final_3);
//final_3 = "4";
GreetingService greetingService = new GreetingService() {
@Override
public void sayMessage(String message) {
System.out.println("Hello " + message);
}
};
greetService1.sayMessage("Runoob");
greetingService.sayMessage("Baidu");
}
interface GreetingService {
void sayMessage(String message);
}
}
如果上面的代码把//final_3 = “4” 取消注释则会报错
2、方法引用
public class Java8Tester {
public static void main(String args[]) {
GreetingService greetingService2 = Java8Tester::setMessage;
Java8Tester java8Tester = new Java8Tester();
GreetingService greetingService3 = java8Tester::setMessage_2;
greetingService2.sayMessage("kuake");
greetingService3.sayMessage("360");
}
interface GreetingService {
void sayMessage(String message);
}
public static void setMessage(String str) {
System.out.println(str + "这是静态方法实现");
}
public void setMessage_2(String str){
System.out.println(str + "非静态方法实现");
}
}
我们有时候想要调用其他方法来快速实现接口方法时,就可以通过方法引用的形式:
如果是静态方法
- 类名::方法名
如果是普通方法
- 对象名::方法名
上面的代码就是使用setMessage和setMessag_2来实现了sayMessage接口方法
使用引用方法来遍历集合:
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5);
//方法引用来输出集合
list.forEach(System.out::println);
//使用lambda来遍历输出集合
list.forEach(element -> {
if (element % 2 == 0) {
System.out.println(element);
}
});
3、流式操作
stream是一个来自于数据源的元素队列,它支持聚合操作
就好像是一个迭代器,单向、不可往复,数据只能遍历一次,遍历后就用尽了
数据源可以是集合、IO对象、数组等
聚合操作:
- map
map是映射每个元素对应的结果
List<Integer> list = Arrays.asList(1,2,3,7,4,3);
List<Integer> collect = list.stream().map(i -> i * 2).collect(Collectors.toList());
collect.forEach(System.out::print);
这里的map(i -> i*2)就是把list中所有元素乘2后再通过collect来组成一个集合
- filter
filter通过设置条件过滤出元素
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
过滤出strings为空的元素
- limit
limit获取指定数量的数据
List<Integer> list = Arrays.asList(1,2,3,7,4,3);
list.stream().limit(3).forEach(System.out::print);
获取前三个数据,但是该方法无法指定两个参数,就像sql中limit(1,3)取出两个数据
- sorted
用于排序操作
List<Integer> list = Arrays.asList(1,2,3,7,4,3);
list.stream().sorted().forEach(System.out::print);
将1,2,3,7,4,3排序输出
Collectors
实现归约操作,将流转化成集合,Collectors可用于返回列表和字符串
在上面的聚合操作后均可以将其转化为对应的列表如map操作所示
Stream的优点:
- 无储存,stream不是一种数据结构,而是某个数据源的视图,数据源可以使集合、数组、IO流
- 对stream的任何操作都不会影响到背后的数据源
- 惰性执行,只有等到用户真的需要结果才运行