代码精进之路
范学雷
Oracle首席软件工程师,Java SE安全组成员,OpenJDK评审成员
立即订阅
6350 人已学习
课程目录
已完结 47 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你写的每一行代码,都是你的名片
免费
第一模块:代码“规范”篇 (16讲)
01 | 从条件运算符说起,反思什么是好代码
02 | 把错误关在笼子里的五道关卡
03 | 优秀程序员的六个关键特质
04 | 代码规范的价值:复盘苹果公司的GoToFail漏洞
05 | 经验总结:如何给你的代码起好名字?
06 | 代码整理的关键逻辑和最佳案例
07 | 写好注释,真的是小菜一碟吗?
08 | 写好声明的“八项纪律”
09 | 怎么用好Java注解?
10 | 异常处理都有哪些陷阱?
11 | 组织好代码段,让人对它“一见钟情”
12丨组织好代码文件,要有“用户思维”
13 | 接口规范,是协作的合约
14 | 怎么写好用户指南?
15 | 编写规范代码的检查清单
16丨代码“规范”篇用户答疑
第二模块:代码“经济”篇 (14讲)
17 | 为什么需要经济的代码?
18丨思考框架:什么样的代码才是高效的代码?
19 | 怎么避免过度设计?
20 | 简单和直观,是永恒的解决方案
21 | 怎么设计一个简单又直观的接口?
22丨高效率,从超越线程同步开始!
23 | 怎么减少内存使用,减轻内存管理负担?
24 | 黑白灰,理解延迟分配的两面性
25 | 使用有序的代码,调动异步的事件
26 | 有哪些招惹麻烦的性能陷阱?
27 | 怎么编写可持续发展的代码?
28 | 怎么尽量“不写”代码?
29 | 编写经济代码的检查清单
30丨“代码经济篇”答疑汇总
第三模块:代码“安全”篇 (14讲)
31 | 为什么安全的代码这么重要?
32 | 如何评估代码的安全缺陷?
33 | 整数的运算有哪些安全威胁?
34 | 数组和集合,可变量的安全陷阱
35 | 怎么处理敏感信息?
36 | 继承有什么安全缺陷?
37 | 边界,信任的分水岭
38 | 对象序列化的危害有多大?
39 | 怎么控制好代码的权力?
40 | 规范,代码长治久安的基础
41 | 预案,代码的主动风险管理
42 | 纵深,代码安全的深度防御
43 | 编写安全代码的最佳实践清单
44 | “代码安全篇”答疑汇总
加餐 (1讲)
Q&A加餐丨关于代码质量,你关心的那些事儿
结束语 (1讲)
结束语|如何成为一个编程好手?
代码精进之路
登录|注册

08 | 写好声明的“八项纪律”

范学雷 2019-01-21
我们在前面讨论了该怎么取一个好名字。在编程语言里,我们使用标识符来表示不同的逻辑和对象。声明就是用来定义这些标识符的。标识符声明的地方,就是取名字和第一次使用名字的地方。这一次,我们聊一聊该怎么声明一个标识符。
“声明”是我们和标识符初次见面的地方,第一印象就显得特别重要。如果我们忘记了,回头能够清晰地找到它,也很重要。如果我们印象模糊了,回头能够重新认识它,对于我们阅读程序也有很大的帮助。
一个标识符,不仅仅只是一个名字。 像人分男女、高矮胖瘦一样,标识符也可以有附加信息,用来增强人们对它的认识。
一个声明,一般至少包含两个部分,一个是标识符的名字,一个是标识符的类型。 比如:
int size;
有的声明,还有修饰和限定部分,比如 Java 的访问控制修饰符(private,public 等):
private int size;
或者 C 语言的存储类别限定符(auto,extern 等):
auto int size;
写声明很简单,但写好声明也并非易事。我们以 Java 语言为例来讨论声明的编码风格。在 Java 语言里,声明可以用来定义类、方法、类变量、局部变量和常量。不同声明的语法有着巨大的差别,但是也有很多共通的地方,你可以把这些思路用在自己熟悉的语言上。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《代码精进之路》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(12)

  • 极客不落🐒
    代码图片建议用 carbon 美化下,可读性会更好:)

    https://carbon.now.sh/

    作者回复: 刚注意到代码图片里的一些规范问题,手误。 看了下carbon,很不错的工具。 谢谢推荐!

    2019-01-29
    1
    4
  • pyhhou
    第28,29,39,40,44行相对应带上大括号会更好
    第39,40,44行属于一行表示多重行为,不便于观察和理解,换行会更好
    第28,31,36,42,47行的代码与前面的代码没有很好的分块,构成不了视觉上面清晰的代码块,在前面加上空行会更好
    第35行命名不够清晰,修改为Map<Character, Character> charMapping = new HashMap<>();
    第29行,就像前面 @背着吉他的大漠狼 同学说的,if 里面的 match 函数其实表示的意义不太明确,读者需要去看 match 函数的大致实现,如果在此之前定义一个boolean isMatched = match(word, pattern); 再将 isMatched 放到 if 里面会好很多;而且把函数直接放在 if 语句里面其实也违反了我们之前提到的单行单一行为的原则,因为运行函数返回结果和表达式条件判断在概念上本就是两个完全不同的行为

    能看到的就这些了,不足之处还请老师和大神们补充

    作者回复: 找的都很棒!

    2019-01-22
    2
  • 王智
    ```
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    class Solution {
        /**
         * Return a list of the words in words that match the given pattern.
         *
         * A word matches the pattern if there exists a permutation of
         * letters p so that after replacing every letter x in the pattern
         * with p(x), we get the desired word.
         *
         * Example:
         * Input: words = ["abc","deq","mee","aqq","dkd","ccc"],
         * pattern = "abb"
         * Output: ["mee","aqq"]
         *
         * Explanation: "mee" matches the pattern because there is
         * a permutation {a -> m, b -> e, ...}.
         *
         * "ccc" does not match the pattern because
         * {a -> c, b -> c, ...} is not a permutation, since a
         * and b map to the same letter.
         */
        public List<String> findAndReplacePattern(String[] words, String pattern) {
            List<String> ans = new ArrayList();
            for (String word : words) {
                if (match(word, pattern)) {
                    ans.add(word);
                }
            }
            return ans;
        }

        public boolean match(String word, String pattern) {
            Map<Character, Character> M = new HashMap();
            for (int i = 0; i < word.length(); ++i) {
                char w = word.charAt(i);
                char p = pattern.charAt(i);
                if (!M.containsKey(w)) {
                    M.put(w, p);
                }
                if (M.get(w) != p) {
                    return false;
                }
            }
            boolean[] seen = new boolean[26];
            for (char p : M.values()) {
                if (seen[p - 'a']) {
                    return false;
                }
                seen[p - 'a'] = true;
            }
            return true;
        }
    }
    ```
    改成我喜欢的格式,虽然不一定准确,但是自己看上去舒服很多

    作者回复: 舒服很多就是收获了。

    2019-01-21
    2
  • allean
    细节无小事,高手不是掌握了降龙十八掌,而是简单的事也能做到极致,学习了。

    作者回复: 质量的事是大事(追求),质量的事是小事(执行)。

    2019-01-21
    2
  • 小文
    还想问个问题就是c++得成员变量初始化可以再声明的时候初始化也可以在构造函数初始化,那哪种比较好呢

    作者回复: 和Java的惯例相比,道理是一样的。C语言,我更倾向于声明时就初始化一点。Java有固定的缺省的值,C语言的缺省值是随机的,一旦初始化遗漏,很多麻烦。

    2019-02-15
    1
  • Lindroid
    length方法直接写在for循环语句中会不会不是很好呢?因为这样每次循环都会调用它去获取word字符的长度,所以我觉得可以在for循环直接声明一个变量,值就是word的字符长度:
            int wordLength = word.length();
            for (int i = 0; i < wordLength; i++) {
               ……
            }

    作者回复: 赞这个发现!

    2019-01-31
    1
  • 背着吉他的大漠狼
    1,if语句尽量不要涉及复杂的表达式,可以用局部变量申明出来
    2,例子中有些许的不同语义的卸载了同一行,写没很好使用花括号
    3,方法体内可以将申明部分与逻辑部分使用空行加强阅读理解

    作者回复: “if语句尽量不要涉及复杂的表达式”,这个经验很赞!

    2019-01-21
    1
  • Demon.Lee
    老师,声明时就初始化,好像我定义那些实体Bean时候,并没有这么做,这个也要看情况吧?

    作者回复: 要看情况,简单的声明优先声明时就初始化。但是也有很多声明,特别是涉及效率的时候,要延迟初始化。我们后面还会专门将延迟初始化。所以,那一段我有加一个这个原则的适用条件。

    2019-01-21
    1
  • Sisyphus235
    声明包含命名规范和类型,命名规范之前的文章探讨过,我觉得这里更重要的是类型。文中提到很多格式上的注意,我补充一些类型上的探讨,使用类型上有很大学问,个人觉得 function 能解决的不用 class,不变的变量要使用 immutable 的类型,避免中间赋值的改变,整型能表达的不用浮点型,金钱等精确度要求高的变量转换成整型。

    另外就是不同代码模块传参的时候,相同声明可能会造成误解,或者一些语言会出现不同 namespace 不可知的变量值改变。

    作者回复: 都是很好的经验! 谢谢分享!

    2019-05-22
  • 拉格朗日的忧桑
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    class Solution {

    private static final char CHAR_VALUE = 'a';


        /**
         * Return a list of the words in words that match the given pattern.
         *
         * A word matches the pattern if there exists a permutation of
         * letters p so that after replacing every letter x in the pattern
         * with p(x), we get the desired word.
         *
         * Example:
         * Input: words = ["abc","deq","mee","aqq","dkd","ccc"],
         * pattern = "abb"
         * Output: ["mee","aqq"]
         *
         * Explanation: "mee" matches the pattern because there is
         * a permutation {a -> m, b -> e, ...}.
         *
         * "ccc" does not match the pattern because
         * {a -> c, b -> c, ...} is not a permutation, since a
         * and b map to the same letter.
         */
        public List<String> findAndReplacePattern(String[] words, String pattern) {
            List<String> result = new ArrayList();

            for (String word: words)
    {
    if (match(word, pattern))
    {

    result.add(word);
    }
                    
    }
                
            return result;
        }

        public boolean match(String word, String pattern) {
            Map<Character, Character> map = new HashMap();

            for (int i = 0; i < word.length(); ++i) {

                char wordChar = word.charAt(i);
                char patternChar = pattern.charAt(i);

                if (!map.containsKey(w))
    {
    map.put(wordChar, patternChar);
    }
                if (map.get(wordChar) != patternChar)
    {
    return false;
    }

            }

            boolean[] seen = new boolean[26];

            for (char charPattern: map.values()) {

                if (seen[charPattern - CHAR_VALUE])
    {
    return false;
    }

                seen[charPattern - CHAR_VALUE] = true;
            }

            return true;
        }
    }
    2019-02-22
  • 小文
    不明白为什么像这种int size, length;一行声明多个的形式要被设计出来,不让用不就得了,唉……

    作者回复: 语言的设计一般要追求的灵活性,使用者就要规避灵活性带来的负面影响。

    2019-02-15
  • 王小豪
    很有用~就是感觉有点短呐😂

    作者回复: 多出来的时间练练题吧😄

    2019-01-21
收起评论
12
返回
顶部