比学习新技术更重要的是思维的改变

程序员是一个苦逼的行业,其中重要的一点就是行业专业知识更新的速度非常快,超过其他绝大部分行业,尤其是前台开发,这些天各种框架思想如雨后春笋层出不穷,有时候买了一本书,书还没有学完,技术可能已经更新或者被淘汰。那么,作为程序员的我们,怎么样才能不被爆炸的知识击昏,切实掌握真正属于自己的技术呢?

从我个人的心得来说,学习技术应该重点学习那种新思想新角度的技术,并使用新的思维来写新学习的技术。大部分技术人员的问题不在于前者,而在于学习了新技术,却还是使用老的思维来写新技术,就好比用马拉火车一样,写者落泪看者伤心!

举例,在前台开发中,MVVM框架的出现,相对于jquery天下的前台是一个非常大的改变,我们学习mvvm框架的时候,首先第一步要从思维上认识到这2种技术的不同,要理解数据驱动概念,理解 “jquery是死的,mvvm是活的” 这点,而不是只是把mvvm框架当作一个模板框架来使用。而在实际工作中,出现过有些水平较差的开发人员,还在使用jquery的思维来写vue的框架,结果是vue的好处没有享受到,整个开发部署过程还变得复杂。

后台开发里面,jdk8由于接口默认实现特性,绝对算得上是一个里程碑,其中最重要的函数式编程的思想。lambda表达式和stream流的学习不算复杂,但你学会了api的使用,你就真的掌握了函数式编程吗?我看未必!

我们来看一道题目,计算 集合中 DeptId 和 Type 相同的数据的num总和。需求很常见,看着很简单,各位写写看?

import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 *  计算 集合中 DeptId 和 Type 相同的数据的num总和
 */
public class Test {

 public static void main(String[] args) {
        List<DataBean> totalStocks = new ArrayList<>();

        DataBean stock1 = new DataBean();
        stock1.setDeptId(2);
        stock1.setType(2);
        stock1.setNum(2);
        totalStocks.add(stock1);

        DataBean stock2 = new DataBean();
        stock2.setDeptId(2);
        stock2.setType(2);
        stock2.setNum(3);
        totalStocks.add(stock2);

        DataBean stock3 = new DataBean();
        stock3.setDeptId(3);
        stock3.setType(3);
        stock3.setNum(5);
        totalStocks.add(stock3);

        DataBean stock4 = new DataBean();
        stock4.setDeptId(3);
        stock4.setType(3);
        stock4.setNum(4);
        totalStocks.add(stock4);

        DataBean stock5 = new DataBean();
        stock5.setDeptId(4);
        stock5.setType(4);
        stock5.setNum(10);
        totalStocks.add(stock5);

 }

}

@Data
class DataBean {

 private int type;

 private int deptId;

 private int num;
}

这条题目是我群里的人问的,他自己用stream写了一个,觉得写的不好,问我应该怎么样写,我当时把这道题目发在群里面,结果发现大部分写得都不太好(建议大家先不要往下看,自己打开ide写写试试)。其中一个常见错误是stream操作中修改了数据,如

//group
Map<String, List<DataBean>> gourps = totalStocks.stream()
 .collect(Collectors.groupingBy(e -> e.getDeptId() + ":" + e.getType()));

// reduce(错误的写法)
List<DataBean> result = gourps.values().stream()
      .reduce(list -> list.stream().reduce((e1, e2) -> {
      e2.setNum(e1.getNum() + e2.getNum());
 return e2;
}).get())
// toList
.collect(Collectors.toList());

System.out.println(result);

还有一种是,自己new了一个ArrayList,然后再流操作之中往list里面加数据的。至于group2次的就不评论了。

我们学习函数式编程里面,函数式强调函数必须是纯函数,不能修改数据,而且是幂等,在stream里面,任何修改数据的行为都是不应该的,修改数据的时候应该返回新对象。所以在里面set数据的,或者往list里面增加数据的,都是不好的写法!我们学习了函数式编程,就应该遵守他的规则和思想。上面的题目,我的写法如下:

List<DataBean> result = totalStocks.stream()
 //group
 .collect(Collectors.groupingBy(e -> e.getDeptId() + ":" + e.getType()))
 // 分组后的list做reduce
 .values().stream().map(list -> list.stream().reduce(Test::combine).get())
 // 收集到list
 .collect(Collectors.toList());

System.out.println(result);


private static DataBean combine(DataBean e1, DataBean e2){
  DataBean e = new DataBean();

  e.setDeptId(e1.getDeptId());
  e.setType(e1.getType());
  e.setNum(e1.getNum() + e2.getNum());

 return e;
}

我们在看另外一种场景,由于不按照函数式思维编写代码,在不同的jdk版本中,结果不一样,可能导致bug

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Demo{
 public  String msg = "初始值";
}

public class LambdaDemo2 {
 public static void main(String[] args) {
        System.out.println("jdk版本:"+ManagementFactory.getRuntimeMXBean().getVmVersion());
        List<Demo> demos  = new ArrayList<Demo>();

        demos.add(new Demo());
        demos.add(new Demo());

 // 这里peek中修改了对象,产生了副作用(side-effects)
 long count = demos.stream().peek(demo -> demo.msg = "peek中修改了").count();
        System.out.println(count);

 // jdk8下下面的demo已经改变
 // jdk10下没有
        demos.stream().forEach(demo -> System.out.println(demo.msg));

 }
}

peek函数,按照函数式编程的规范,是调试用的,是个中间操作,如果你在里面修改了对象,看上去没有问题,但是在JDK8和JDK10中,2种运行结果不一致,JDK10种peek方法直接跳过了。

所以,我们学习一个新技术,可以从下面几个层次了解推进,产生的背景?和之前的技术有什么区别?他的思想(风格)是什么?主要的API和套路。如函数式编程,要了解和命令式编程的区别,一开始可能不太理解,多看几个贴,先有个模糊的概念。然后再看看函数式是怎么样的风格?而不是当作一个新的类库/工作类来使用(很多人是当作工具类使用的想法)。最后系统学习api。当然最重要的还是多写,写完之后看看是不是符合函数式编程的风格,如果看着别扭那就是那个环节出现了问题。

总结,我们学习新技术的同时,除了API的使用之外,最重要的是改变思维,使用新技术的思维来写新的代码,一开始可能有点痛苦,但多写几次之后就会适应,就会感觉到新的技术给我们带来的好处,这是成长的必经之路!

猜你喜欢

转载自blog.csdn.net/zl1zl2zl3/article/details/86478181