这个用法最初是在工作中读浩哥代码看到的,由于当时时间紧张,粗略看了一下以为就是个生成 List 的方法,于我而言其最多使用的地方在 Entity、Dto、From 间的互转,以至于在今后所有的涉及到转换的地方我都开始倾向于使用此方法,但是突然有一次就掉坑了…

先看看一段正常的代码1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63public class{

public static void main(String[] args){

List userList = Lists.newArrayList(new User("Alex", 12, "Play"), new User("August", 18, "Play"), new User("Ada", 11, "Play"));

List userFormList = new ArrayList(userList.size());

userFormList = Lists.transform(userList, new Function(){

public UserForm apply(User input){

UserForm form = new UserForm();

form.setName(input.getName());

form.setAge(input.getAge());

form.setHobby(input.getHobby());

return form;

}

});

for (UserForm form : userFormList){

System.out.println(form);

}

}

}

@Getter

@Setter

class User{

String name;

Integer age;

String hobby;

public User(){

}

public User(String name, Integer age, String hobby){

super();

this.name = name;

this.age = age;

this.hobby = hobby;

}

public String toString(){

return "User [name=" + name + ", age=" + age + ", hobby=" + hobby + "]";

}

}

@Getter

@Setter

class UserForm{

String name;

Integer age;

String hobby;

Integer id;

public String toString(){

return "UserForm [name=" + name + ", age=" + age + ", hobby=" + hobby + ", Id=" + id +"]";

}

}

输出结果:1

2

3UserForm [name=Alex, age=12, hobby=Play, Id=null]

UserForm [name=August, age=18, hobby=Play, Id=null]

UserForm [name=Ada, age=11, hobby=Play, Id=null]

这段代码作用就是快速通过 List 生成 List,没什么毛病对吧,接下来我们想在生成的 List 中修改 hobby 和 Id,看看会发生什么:1

2

3

4

5

6

7

8

9Random random = new Random();

for (UserForm form : userFormList){

form.setHobby("Study, It makes me happy~");

form.setId(String.valueOf(random.nextInt(20)));

System.out.println(form);

}

for (UserForm form : userFormList){

System.out.println(form);

}

输出结果:1

2

3

4

5

6

7UserForm [name=Alex, age=12, hobby=Study, It makes me happy~, Id=15]

UserForm [name=August, age=18, hobby=Study, It makes me happy~, Id=17]

UserForm [name=Ada, age=11, hobby=Study, It makes me happy~, Id=2]

UserForm [name=Alex, age=12, hobby=Play, Id=null]

UserForm [name=August, age=18, hobby=Play, Id=null]

UserForm [name=Ada, age=11, hobby=Play, Id=null]

咦! 第一次迭代的时候输出结果和我们预期一样,但是第二次的结果怎么显示成这个样子??

这么神奇的吗??

Debug 分析问题

带着疑惑,我们 Debug 走一下流程

首先在执行 Lists.transform() 的时候会 先判断是否是 RandomAccess 类型,结合 RandomAccess 展开树我们可以发现,ArrayList 实现了 RandomAccess 接口

紧接着会创建 TransformingRandomAccessList 类,并赋值 fromList 和 function

创建完成之后,function 是没有立即执行的,此时代码直接跳转到了 迭代 userFormList 的地方

到此时开始执行 TransformingRandomAccessList 中的 listIterator() 方法开始迭代生成数据,这时候每次都会执行 transform() 方法,传入 F(From) 来源 User 类型数据,生成 T(Traget) 目标 UserForm 类型数据

说说我的理解:我们的 userFormList 在执行 Lists.transform 后是没有立刻被赋值的,它只是被转换成了 TransformingRandomAccessList 类型,此类型 重写了迭代器,每次当我们迭代 userFormList 时候,它才会调用 function 进行赋值。

带着上面的理解我们来重新看一次这段代码:1

2

3

4

5

6

7

8

9Random random = new Random();

for (UserForm form : userFormList){

form.setHobby("Study, It makes me happy~");

form.setId(String.valueOf(random.nextInt(20)));

System.out.println(form);

}

for (UserForm form : userFormList){

System.out.println(form);

}

userFormList 在第一次迭代的时候会执行 Function 中的 UserForm form = new UserForm(); 此时会创建新的 UserForm,然后进行 set 不同的值,在我们第二次进行 迭代的时候,此时又会执行 Function 中的 UserForm form = new UserForm(); 这时候会再次创建 UserForm,当你 Debug 的时候会发现两次创建的 UserForm 地址是不一样的,这样就能解释为什么我们 set 的时候不起作用啦~

带着上面得出的结论来看看源码中的官方文档:

可以说官方文档已经安排得明明白白的,它提到 Lists.transform 返回的每一个元素是 function 执行后的结果,其返回的 list 就是一个转换后的 “视图”,修改 原有的 list 会影响到现有的 list。并且 function 方法是不可逆的,生成的 list 不支持 add、addAll、set 方法,这个 function 是类似一种懒加载的机制,只有在需要的时候被调用,如果你想让返回的 List 不受此限制的话,需要自己动手 copy…

最后它还提了一句,此方法返回的 list 在你进行序列化的时候可能出现一些奇怪的操作,所以不推荐序列化。

突破 set 无法成功

在了解这个方法之后,我发现这个方法限制还蛮多的,于是找到浩哥,问了一下此方法用意,原以为是有性能上的优化,结果发现只是为了代码简洁一点,性能对比还没有普通写法来得快…

之前我们发现需要 set 的时候不能再次迭代 List,所以只有写在 Function 中才能完成我们的迭代咯,于是我又模拟了一下最常见的情况,我们稍微修改一下现有的代码:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65@Getter

@Setter

class User{

String name;

Integer age;

String hobby;

Integer id;

public User(){

}

public User(String name, Integer age, String hobby, Integer id){

super();

this.name = name;

this.age = age;

this.hobby = hobby;

this.id = id;

}

public String toString(){

return "User [name=" + name + ", age=" + age + ", hobby=" + hobby + ", id=" + id + "]";

}

}

@Getter

@Setter

class UserForm{

String name;

Integer age;

String hobby;

String secret;

public String toString(){

return "UserForm [name=" + name + ", age=" + age + ", hobby=" + hobby + ", Id=" + secret + "]";

}

}

@Test

public void ttest(){

List userList = Lists.newArrayList(new User("Alex", 12, "Play", 1), new User("August", 18, "Play", 2), new User("Ada", 11, "Play", 3));

Map secretMap = new HashMap();

secretMap.put(1, "biubiubiu~");

secretMap.put(2, "miaomiaomiao~");

secretMap.put(3, "qiuqiuqiu~");

List userFormList = new ArrayList(userList.size());

userFormList = Lists.transform(userList, new Function(){

@Override

public UserForm apply(User user){

UserForm form = new UserForm();

form.setName(user.getName());

form.setAge(user.getAge());

form.setHobby(user.getHobby());

form.setSecret(secretMap.get(user.getId()));

return form;

}

});

}

注意这里: form.setSecret(secretMap.get(user.getId())); 这里编译的时候会报错:

Cannot refer to non-final local variable secretMap define in an enclosing scope.

提示 secretMap 不是 final 修饰的变量,难道还需要使用 final 类型的变量吗? (至于为什么需要 final 修饰的变量,这个问题后面有时间再研究咯~)

将上面的代码改一下就能生效啦:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29@Test

public void ttest(){

List userList = Lists.newArrayList(new User("Alex", 12, "Play", 1), new User("August", 18, "Play", 2), new User("Ada", 11, "Play", 3));

Map secretMap = new HashMap();

secretMap.put(1, "biubiubiu~");

secretMap.put(2, "miaomiaomiao~");

secretMap.put(3, "qiuqiuqiu~");

final Map finalSecretMap = secretMap;

List userFormList = new ArrayList(userList.size());

userFormList = Lists.transform(userList, new Function(){

@Override

public UserForm apply(User user){

UserForm form = new UserForm();

form.setName(user.getName());

form.setAge(user.getAge());

form.setHobby(user.getHobby());

form.setSecret(finalSecretMap.get(user.getId()));

return form;

}

});

for (UserForm form : userFormList){

System.out.println(form);

}

}

再看看输出结果:1

2

3UserForm [name=Alex, age=12, hobby=Play, Id=biubiubiu~]

UserForm [name=August, age=18, hobby=Play, Id=miaomiaomiao~]

UserForm [name=Ada, age=11, hobby=Play, Id=qiuqiuqiu~]

Nice~~~

java解锁_Java 姿势解锁 —— Lists.transform相关推荐

  1. [解锁新姿势] 回想起被 `if-else` 支配的恐惧,我们要打倒 if - else

    前言 [解锁新姿势] 兄dei,你代码需要优化了 在之前文章说到,简单 if-else,可以使用 卫语句 进行优化.但是在实际开发中,往往不是简单 if-else 结构,我们通常会不经意间写下如下代码 ...

  2. [解锁新姿势] 兄dei 我感觉你在写bug

    前言: 继上篇 [解锁新姿势] 兄dei,你代码需要优化了 介绍一些代码的优化的小技巧. 但是我们除了在代码编写上需要优雅, 还需要编写对应的测试用例, 以此来保证代码的质量. 在这篇我们继续在学习如 ...

  3. android 解锁mac,论一台笔记本三个不同系统的玩法,解锁正确姿势

    原标题:论一台笔记本三个不同系统的玩法,解锁正确姿势 关于<折腾永无止境>的文章... 所以不打算长篇幅介绍怎么安装.步骤.怎么折腾的教科书,不懂?隔壁度娘给你答案! 目标非常明确:要榨干 ...

  4. 计算机怎样发现路由器上u盘,竟然能当路由器 优盘技巧解锁更多姿势

    1优盘技巧解锁更多姿势 提到优盘,我们都知道是它非常方便的工具,技术的不断发展进步让优盘在容量增加的同时体积也在边小,也让优盘更加亲民易用. 小巧的优盘让使用更方便 很多人都有一个或多个优盘,不管是拷 ...

  5. android解锁win,Win10电脑解锁新姿势:WP/安卓手机、微软手环当钥匙

    IT之家讯 微软在官方网站公布了Win10的开发路线图,其中描述了目前已经实现的功能.正在预览测试以及正在开发中的功能.根据描述,微软正在开发一种全新的Win10电脑解锁方式. 首先,你可以使用自己的 ...

  6. java 锁_Java 锁之我见

    今天我们来聊聊 Java 里面的各种锁:偏向锁.轻量级锁.重量级锁,以及三个锁之间是如何进行锁膨胀的. 众所周知,线程阻塞带来的上下文切换的代价是很大的,Java 为了尽量减少上下文的切换从而引入了更 ...

  7. guava Lists.transform 踩过的坑

    2019独角兽企业重金招聘Python工程师标准>>> package com.case;import java.util.List;import com.google.common ...

  8. 项目需求讨论-APP手势解锁及指纹解锁

    好久没写文章了,最近也比较偷懒,今天继续讨论我实际开发中遇到的需求,那就是关于APP解锁,大家都知道.现在越来越多的APP在填入账号密码后,第二次登录后,基本不会再次重复输入账号密码了.而是快捷登录, ...

  9. iOS指纹解锁和手势解锁

    前言 一直想写博客来着,一来可以记录一些自己学习和研究的东西,二来也可以将自己写的一些东西分享出去,给他人参考,还可能收到他人的一些建议,从而完善自己的项目和提升自己的技术,这也是一种很好的技术交流方 ...

最新文章

  1. (传送门)instant run原理
  2. 世界人工智能大会圆桌实录:AI与产业融合创新的挑战与机遇
  3. android 双击home退出程序,Android项目实战(五十五):部分机型点击home再点图标进入程序不保留再之前界面的问题...
  4. 最好的电脑系统_热键被占用怎么办?电脑系统 程序 游戏热键被占用冲突如何解决?...
  5. 简单英文题 24 Divisor and Multiple(python)
  6. 光纤传感器实验模块_实验3振动测量试验模块.doc
  7. 17、SpringBoot------整合dubbo
  8. swift拖放的按钮如何在后台设置点击事件 www.cnblogs.com/foxting/p/SWIFT.html
  9. linux管理员下安装网易云,在Ubuntu 18.10系统中安装网易云音乐的方法
  10. Spring Boot+Spring Security:基于URL动态权限:自定义Filter - 第17篇
  11. Hexo Next 5.x 升级 6.x
  12. 直播网站html代码,怎么生成嵌入网页直播的HTML代码
  13. 3037 插板法+lucas
  14. 西岸风格合成器-Eventide Newfangled Audio Generate 1.2.1 WiN
  15. Nginx支持url不区分大小写
  16. Tor 在 linux上使用
  17. VScode提升效率技巧教程
  18. 简述python的书写规则_python3 基本书写规范
  19. 面向维基百科的领域知识演化关系抽取
  20. 抽象类,抽象函数课后习题·唐老狮

热门文章

  1. Activiti工作流实战-2
  2. 并发异步处理队列 .NET 4.5+ (改进性能计数器) 2013-11-16
  3. 架设自己的WebDAV服务器作为AutoCAD WS的数据存储
  4. 鼠标滚动缩放图片效果
  5. 关于perl中变量内插问题的讨论
  6. iView 3.3.0 发布,基于 Vue.js 的企业级 UI 组件库
  7. Android笔记-网络篇:网络状态
  8. Java并发基础构建模块简介
  9. linux下VNC配置详解
  10. 疯狂java讲义之流程控制与数组