String、ArrayList、HashMap 这些基础类,什么时候用错最伤性能
很多人学 Java 时,最先熟悉的就是 String、ArrayList、HashMap 这些基础类。也正因为太熟了,项目里反而经常是在它们身上出问题。不是因为类本身复杂,而是因为大家太容易“顺手就用”,很少停下来想当前场景到底合不合适。
很多人学 Java 时,最先熟悉的就是 String、ArrayList、HashMap 这些基础类。也正因为太熟了,项目里反而经常是在它们身上出问题。不是因为类本身复杂,而是因为大家太容易“顺手就用”,很少停下来想当前场景到底合不合适。
第一次写 Dockerfile 时,很容易把它理解成“按步骤把环境搭起来”就好。
可 2017 年我在反复构建 Node 项目镜像时,越来越明显地感觉到:Dockerfile 里的 COPY 顺序不只是可读性问题,它会直接决定构建缓存是不是容易失效。
现在大家一提 Docker 镜像优化,很容易先想到多阶段构建。但 2017 年那会儿,很多团队日常还没有把这套玩法完全用顺。想让镜像体积别太夸张,往往还是靠一些更基础、也更朴素的习惯。
用 glob 做批处理时,大家通常会先想“我该怎么把目标文件匹配出来”。
可 2017 年我自己写这类脚本越来越多之后,反而最警惕另外一件事:是不是把不该处理的生成目录也一起扫进来了。
第一次在 Node.js 脚本里用 glob,会有一种很爽的感觉:以前得自己递归目录、判断后缀,现在一条模式就能把文件找出来。可真把它用进构建脚本、批处理脚本、资源扫描脚本以后,就会发现路径这件事比模式本身更容易出问题。
Java 项目里很容易出现一种“看上去很稳”的异常处理:每一层都在 catch,每一层都在包一层自己的提示,最后用户确实看不到原始异常了,但开发排查时也很难再看到真正的现场。
2017 年我在处理一些线上问题时,对这一点的体会越来越深。
“接口和抽象类怎么选”几乎是每个 Java 学习阶段都会碰到的问题。
很多回答会从语法、继承、默认实现这些点切入,这些都没错。但 2017 年我在项目里慢慢形成的判断是:真正决定选择的,常常不是当前写起来哪个方便,而是未来变化会往哪个方向长。
Java 8 刚出来那阵,很多人讨论接口默认方法,讨论点常常是“它是不是打破了接口的纯粹性”。我后来在项目里真正用过几次后,反而觉得更实际的问题是:哪些重复代码适合放进去,哪些不适合。
很多人学日志排查,最先接触的是 tail -f。这当然很好,因为它直观、反馈快。
但 2017 年我自己排查线上日志越来越多之后,一个很明显的体会是:只会单独用某一个命令,和真正排日志顺手,中间差着一层“能不能把工具组合起来”。
早些年排查线上日志,很多人的第一反应都是 tail -f。我也一样,因为它直接、顺手,而且大多数教程都是这么教的。可 2017 年之后,随着 systemd 越来越常见,我慢慢发现,如果 Node 服务本身就是被 systemd 接管的,只盯着 tail 其实会漏掉很多关键信息。