我这些实例,包含如下:
Java 8 中 list 和 map 的循环遍历 - forEach的用法。
Java 8 中对 list 和 map 集合的过滤 - filter的用法。
Java 8 中对stream的操作,filter操作。。
一般都是看到了别人的写法,或者是编辑器提示你可以这么写,你才这么写,写了之后。
发现;唉,我不一定懂,我是改成这个lambda表达式呢,还是就按之前Java 7 的写法写呢?
现在,我就简单的把 8 和 7 之间相互的对应起来。
理论说的再多,你也记不住,记住也没用。还不如代码来的实在。
(说实话,这东西,2014年都出来了,现在我才知道。也不能说才知道,只是说不像for each 循环那样,天天用。)
首先,我们需要一个操作对象,为了贴近实际,咱就不简单的使用字符串类啥的简单的类啦,咱自己新建个用户类,在文章底部。
下面就要开始搞啦。
先是获得个操作集合(map,list)的方法。
/**
* 获得一个list集合
*/
private static List<User> getLoopList() {
List<User> all = Lists.newArrayList();
for (int i = 0; i < 10; i++) {
all.add(new User("lxk_" + i, "pwd_" + i));
}
return all;
}
/**
* 获得一个map集合
*/
private static Map<Integer, Integer> getLoopMap() {
Map<Integer, Integer> map = Maps.newHashMap();
for (int i = 0; i < 10; i++) {
map.put(i, i);
}
return map;
}
还有个打印分行符的方法,为了打印操作方便,咱写个方法调用的时候,也简单,也可以重用。不然,你每次 打印个分行符,你还得复制那么一长串代码,虽然都是复制,我复制一个方法名快,还是你复制一行代码快。体现的是代码封装重用的思想。。。。呵呵,扯远啦。。虽然这个方法,看起来很是简单的样子。
/**
* 打印分行符公共方法
*/
private static void println() {
System.out.println("___________________我是分行符___________________");
}
获得了集合之后,就是循环以及操作这个集合啦。简单对比 7 和 8 的实现不同。
下面先看看,在循环遍历的时候的差别:
/**
* 测试集合(list,map)循环
*/
private static void testLoop() {
List<User> list = getLoopList();
beforeLoopList(list);
lambdaLoopList(list);
Map<Integer, Integer> map = getLoopMap();
beforeLoopMap(map);
lambdaLoopMap(map);
}
/**
* 以前循环一个集合,for和foreach循环
*/
private static void beforeLoopList(List<User> list) {
for (User user : list) {
System.out.println(user.toString());
}
println();
}
/**
* 使用lambda循环一个集合
*/
private static void lambdaLoopList(List<User> list) {
//三行循环效果相同
//list.forEach(user -> System.out.println(user.toString()));
//list.forEach(user -> System.out.println(user));//下面一行代码就是简写形式
list.forEach(System.out::println);
println();
}
/**
* Java 7 的map的遍历
*/
private static void beforeLoopMap(Map<Integer, Integer> map) {
System.out.println("Java 7 遍历map");
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("k " + entry.getKey() + " v " + entry.getValue());
}
for (Integer key : map.keySet()) {
System.out.println("k " + key);
}
for (Integer value : map.values()) {
System.out.println("v " + value);
}
println();
}
/**
* Java 8 的map的遍历
*/
private static void lambdaLoopMap(Map<Integer, Integer> map) {
System.out.println("Java 8 遍历map");
map.forEach((k, v) -> System.out.println("k " + k + " v " + v));
println();
}
Java 8 的for each 变成啦 forEach ,就是上面代码所展示的那样。
前面的user是自己声明的变量, -> 这个箭头后面的呢就是对这个变量的操作。后面要是多行代码的话,就的弄个大括号,括起来。
没有注释的那行代码,看着就是相当的精炼。。。。
左边是容器(可以是类名,实例名),中间是”::”,右边是相应的方法名。
上面循环遍历的姿势会了,那么就想在循环遍历的时候,顺带操作修改一下集合内容,
下面看循环遍历操作集合的时候的差别
/**
* 测试循环的时候,顺带操作集合中的内容。
*/
private static void testLoopOperate() {
List<User> list = getLoopList();
lambdaOperateList(list);
Map<Integer, Integer> map = getLoopMap();
lambdaOperateMap(map);
}
private static void lambdaOperateList(List<User> list) {
System.out.println("对list集合进行操作:user's name + “_1” ");
//list.forEach(user -> user.setName(user.getName() + "_1"));
list.forEach(user -> {
String name = user.getName();
user.setName(name + "_1");
//在循环的时候,不能修改list结构(包括新增和删除).
//不然会出现此异常:Exception in thread "main" java.util.ConcurrentModificationException
//if(user.getPwd().contains("1")){
// list.remove(user);
//}
//if(user.getPwd().contains("1")){a
// list.add(new User("10","10"));
//}
});
//操作完,循环输出一下,看下是否操作OK。
list.forEach(System.out::println);
println();
}
private static void lambdaOperateMap(Map<Integer, Integer> map) {
System.out.println("对map集合进行操作:map's value + 10 ");
map.forEach((k, v) -> {
v = v + 10;
map.put(k, v);//更新。
//在循环的时候,不能修改map结构(包括新增和删除).
//不然会出现此异常:Exception in thread "main" java.util.ConcurrentModificationException
//if(k == 1){
// map.remove(k);
//}
//if(k == 9){
// map.put(10,10);//添加,
//}
});
lambdaLoopMap(map);
println();
}
注意,上面我说的那些个异常的情况,那些你在Java 7 里面循环的时候,要是也这么干,也是会出异常的。
看上面代码的运行结果:
Java 8 还有个 stream ,流,这个流不是咱一般的文件流的那个流。
先看这个stream里面的filter方法:对操作集合,按某个条件进行过滤。、
/**
* 测试collection.stream().filter()
*/
private static void testStreamFilter() {
List<User> list = getLoopList();
System.out.println("对集合进行过滤:user name 包含 1 的用户");
List<User> filtered = list.stream().filter(s -> s.getName().contains("1")).collect(Collectors.toList());
filtered.forEach(user -> System.out.println(user.toString()));
println();
}
上面代码的运行结过:
一般的集合类,就是咱常用的list的实现类,都可以直接调用这个方法。hashmap之类的除外。
说到原理:那就是在Collection类里面有stream()这个方法,所以,一般的继承的这个类的类都可以直接调用stream(),获得流。继而进行下一步操作。
Java 8 里面,对接口,也就是interface,进行了扩展,以前,咱只能简单的声明一些方法,并不能去实现这些方法,要实现,那只能到抽象类里面去实现。
现在接口里面也可以实现方法啦,只是要在这个方法的前面加一个关键字:default。。。。这个stream()就是这么实现的。
关于这个流Stream,Java 8 里面有个并行流的概念,这个就大概了解下。
流操作可以是顺序的,也可以是并行的。顺序操作通过单线程执行,而并行操作则通过多线程执行。
这个升级就是充分的利用计算机的多核的高科技,大家都这么说,我也就这么说一下咯。至于两者的差别。
看下面的实验现象吧;
Java 8 lambda stream forEach parallel 等循环与Java 7 for each 循环耗时测试
这个链接里面展示了串行和并行同时去打印一个集合的元素的时候的差别。可以简单看下。
关于filter 用法,就是里面就是个过滤这个集合的条件,必须是返回true 或者false。才可以。不然就OK啦。
/**
* 测试collection.stream().map()
*/
private static void testStreamMap() {
List<User> list = getLoopList();
System.out.println("对集合进行操作:user name + “1” ");
List<String> nameList = list.stream().map(User::getName).collect(Collectors.toList());
nameList.forEach(System.out::print);
println();
}
运行结果:
这个map也算是操作集合数据,
下面再看个简单的例子:
/**
* 测试用法,稍复杂的串行操作。
* 过滤空值;去重;排序;循环输出。
*/
private static void testNumber() {
List<Integer> integers = Arrays.asList(1, 3, null, 8, 7, 8, 13, 10);
integers.stream().filter(Objects::nonNull).distinct().sorted().forEach(System.out::println);
}
运行结果:
代码操作中使用的model类
package com.lxk.model;
/**
* 用户model
* <p>
* Created by lxk on 2017/8/31
*/
public class User {
private String name;
private String pwd;
public User() {
}
public User(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
这个类,很简单,也就是一个用户名和密码两个字符串的属性,然后就再有一个toString方法。
哦,还有2个构造函数,你要问为什么这有2个构造函数吗?
我为啥写那个不带参数的构造函数呢?因为,这个不带参数的构造函数 ,你不用,但是,一般的spring,等框架是要用的。咱还是不要省了。