JAVA 8 (jdk 1.8)
部分新特性
- Lambda表达式
- 默认方法
- Stream API
Lambda的介绍
lambda的语法表达式:
(parameters)-> expression
(parameters) ->{ statements; }
看使用场景来决定使用哪种。类似于if要不要加{}
parameters:请求参数不需要声明参数类型,编译器可以统一识别参数值【可以写上参数类型方便阅读】。
可选参数圆括号:一个参数无需定义圆括号【也可以写】,但是多个参数一定需要定义圆括号。
可选大括号:大括号为代码块,如果只包含一条语句,可以不使用。
可选的返回关键字:如果主体只有一个表达式返回值,编译器会自动返回值,大括号只需指明表达式返回了一个数值。
一般lambda与函数式接口一起使用
**函数式接口:**类由interface修饰,仅仅只包含一个抽象方法的接口。但是java8引入了接口的默认方法。
因为interface修饰的类仅仅包含一个抽象方法,所以,使用lambda表达式,可以自动定位到方法,可以自动匹配到函数参数
比如:下面这个接口类,只有一个函数void accept(T t);
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
......
}
官方的案例:
@FunctionalInterface只是一个单纯的标签,标注该类仅仅只包含一个抽象方法的接口
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
......
}
Stream流的介绍与Lambda的使用
lambda表达式与Stream连用比较多,顺便了解stream
流的数据来源:集合,数组,I/O,产生器generator等。
聚合操作:类似于SQL一样的操作,比如fifter,map,reduce,find,match,sorted和forEach
生成流
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流
forEach
forEach是stream提供的新方法,来迭代每个流中的数据。
我们查看forEach的源码发现:
void forEach(Consumer<? super T> action);
参数为Consumer对象,查看Consumer源码:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
......
该类由@FunctionalInterface可知,我们可以使用lambda表达式声明一个Consumer对象
Consumer<Integer> consumer = integer ->
System.out.println("当前流的数据:"+integer);
遍历一个Integer的list使用Stream 和 Lambda表达式可如下:
List<Integer> list = Arrays.asList(10,52,15,32,45,01,20);
Consumer<Integer> consumer = integer ->
System.out.println("当前流的数据:"+integer);
list.stream().forEach(consumer);
也可以写为:
list.stream().forEach(integer -> System.out.println("当前流的数据:"+integer));
运行结果如下:
当前流的数据:10
当前流的数据:52
当前流的数据:15
当前流的数据:32
当前流的数据:45
当前流的数据:1
当前流的数据:20
如果使用parallelStream()创建流,打印顺序并不是预先设定好的,得知parallelStream为并行。【以前看到过一个帖子说是开启线程,俺没有验证】
filter
filter通过设置条件过滤元素,定义一个Student实体类,找出叫张三的学生
查看filter源码以及filter的参数源码如下:
//filter源码
Stream<T> filter(Predicate<? super T> predicate);
//filter需要的函数接口源码 该源码返回boolean类型,得知,我们如果返回true则保留
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
......
}
完成代码如下:
List<Student> students = Arrays.asList(
new Student("王五",1),
new Student("张三",2),
new Student("李四",3),
new Student("张三",4),
new Student("田六",5),
new Student("王五",6),
new Student("赵七",7)
);
students.stream()//开启流
.filter(item->"张三".equals(item.getName()))//过滤张三
.collect(Collectors.toList())//设置为新的list【需要设置新对象使用,这里用不用都可以】
.forEach(zs-> System.out.println("name:"+zs.getName()+",ID:"+zs.getId()));//打印
执行结果如下:
name:张三,ID:2
name:张三,ID:4
上面介绍了如何使用lambda ,可以将lambda当做一个特殊的参数【实现了代码块参数】
**
Stream下的函数:
**
filter
//strean下的函数
Stream<T> filter(Predicate<? super T> predicate);
//该函数需要的参数对应的参数类型
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
代码应用
System.out.println("----------------------------------------------------------");
List<Integer> ints = Arrays.asList(1,20,40,33,5,2,2,40);
ints.stream().filter(a->a>=20)
.forEach(item-> System.out.println(item));
System.out.println("----------------------------------------------------------");
执行结果如下
------------------------------------------------------------------------
20
40
33
40
------------------------------------------------------------------------
map(我将这个理解为类型转换)
//strean下的函数
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//该函数需要的参数对应的参数类型
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
代码应用(注意到apply是有返回值的,如果一行代码可以省略,如果写的{}就不能省略)
List<Integer> ints = Arrays.asList(1,20,40,33,5,2,2,40);
System.out.println("---------------------------------------------------------");
ints.stream().map(integer -> String.valueOf(integer+1))
.forEach(item-> System.out.println(item+1));
System.out.println("---------------------------------------------------------");
运行结果(map将Integer类型转换为String类型)
-----------------------------------------------
21
211
411
341
61
31
31
411
-----------------------------------------------
mapToInt 将数据类型转换为int类型。下面的代码没有省略 return,没有省略声明lambda表达式的声明
System.out.println("-----------------------------------------------");
//声明一个String类型数组,为了省事,就cp上面的代码了。
List<String> sint = ints.stream().map(integer -> String.valueOf(integer+1)).collect(Collectors.toList());
//声明ToIntFunction实例,并且实现接口里的唯一一个抽象方法
ToIntFunction<String> stringToIntFunction = intString ->{
return Integer.parseInt(intString);
};
//实现IntStream.forEach()需要的IntConsumer 实例,并且实现接口抽象方法
IntConsumer intConsumer = item-> System.out.println(item+50);
sint.stream().mapToInt(stringToIntFunction).forEach(intConsumer);
System.out.println("-----------------------------------------------");
运行结果:
-----------------------------------------------
52
71
91
84
56
53
53
91
-----------------------------------------------
mapToLong
mapToDouble
Stream下的这两个函数,与mapToInt类似。就不一一举例了。
该图来源:https://blog.csdn.net/Mark_Chao/article/details/80810030
stream还有排序等等等等都可以用查看源码,来得到是如何使用以及它的功能。
看了源码哪怕不了解原理,知道怎么用还是能达到的。
其他细节参考各种学习网站都可以,这里只是记录本人学习过程,以及使用后记录下来的。