精华内容
下载资源
问答
  • 为什么强烈禁止开发人员使用isSuccess作为变量名

    千次阅读 多人点赞 2019-05-07 09:58:57
    在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否...一般情况下,我们可以以下四种方式来定义一个布尔类型的成员变量: ...

    在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的。

    关于这个"本次请求是否成功"的字段的定义,其实是有很多种讲究和坑的,稍有不慎就会掉入坑里,作者在很久之前就遇到过类似的问题,本文就来围绕这个简单分析一下。到底该如何定一个布尔类型的成员变量。

    一般情况下,我们可以有以下四种方式来定义一个布尔类型的成员变量:

    boolean success
    boolean isSuccess
    Boolean success
    Boolean isSuccess
    

    以上四种定义形式,你日常开发中最常用的是哪种呢?到底哪一种才是正确的使用姿势呢?

    通过观察我们可以发现,前两种和后两种的主要区别是变量的类型不同,前者使用的是boolean,后者使用的是Boolean。

    另外,第一种和第三种在定义变量的时候,变量命名是success,而另外两种使用isSuccess来命名的。

    首先,我们来分析一下,到底应该是用success来命名,还是使用isSuccess更好一点。

    success 还是 isSuccess

    到底应该是用success还是isSuccess来给变量命名呢?从语义上面来讲,两种命名方式都可以讲的通,并且也都没有歧义。那么还有什么原则可以参考来让我们做选择呢。

    在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:

    -w656

    那么,为什么会有这样的规定呢?我们看一下POJO中布尔类型变量不同的命名有什么区别吧。

    class Model1  {
        private Boolean isSuccess;
        public void setSuccess(Boolean success) {
            isSuccess = success;
        }
        public Boolean getSuccess() {
            return isSuccess;
        }
     }
    
    class Model2 {
        private Boolean success;
        public Boolean getSuccess() {
            return success;
        }
        public void setSuccess(Boolean success) {
            this.success = success;
        }
    }
    
    class Model3 {
        private boolean isSuccess;
        public boolean isSuccess() {
            return isSuccess;
        }
        public void setSuccess(boolean success) {
            isSuccess = success;
        }
    }
    
    class Model4 {
        private boolean success;
        public boolean isSuccess() {
            return success;
        }
        public void setSuccess(boolean success) {
            this.success = success;
        }
    }
    

    以上代码的setter/getter是使用Intellij IDEA自动生成的,仔细观察以上代码,你会发现以下规律:

    • 基本类型自动生成的getter和setter方法,名称都是isXXX()setXXX()形式的。
    • 包装类型自动生成的getter和setter方法,名称都是getXXX()setXXX()形式的。

    既然,我们已经达成一致共识使用基本类型boolean来定义成员变量了,那么我们再来具体看下Model3和Model4中的setter/getter有何区别。

    我们可以发现,虽然Model3和Model4中的成员变量的名称不同,一个是success,另外一个是isSuccess,但是他们自动生成的getter和setter方法名称都是isSuccesssetSuccess

    Java Bean中关于setter/getter的规范

    关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans™ Specification规定,如果是普通的参数propertyName,要以以下方式定义其setter/getter:

    public <PropertyType> get<PropertyName>();
    public void set<PropertyName>(<PropertyType> a);
    

    但是,布尔类型的变量propertyName则是单独定义的:

    public boolean is<PropertyName>();
    public void set<PropertyName>(boolean m);
    

    -w687

    通过对照这份JavaBeans规范,我们发现,在Model4中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。

    那这样做会带来什么问题呢。

    在一般情况下,其实是没有影响的。但是有一种特殊情况就会有问题,那就是发生序列化的时候。

    序列化带来的影响

    关于序列化和反序列化请参考Java对象的序列化与反序列化。我们这里拿比较常用的JSON序列化来举例,看看看常用的fastJson、jackson和Gson之间有何区别:

    public class BooleanMainTest {
    
        public static void main(String[] args) throws IOException {
            //定一个Model3类型
            Model3 model3 = new Model3();
            model3.setSuccess(true);
    
            //使用fastjson(1.2.16)序列化model3成字符串并输出
            System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model3));
    
            //使用Gson(2.8.5)序列化model3成字符串并输出
            Gson gson =new Gson();
            System.out.println("Serializable Result With Gson :" +gson.toJson(model3));
    
            //使用jackson(2.9.7)序列化model3成字符串并输出
            ObjectMapper om = new ObjectMapper();
            System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));
        }
    
    }
    
    class Model3 implements Serializable {
    
        private static final long serialVersionUID = 1836697963736227954L;
        private boolean isSuccess;
        public boolean isSuccess() {
            return isSuccess;
        }
        public void setSuccess(boolean success) {
            isSuccess = success;
        }
        public String getHollis(){
            return "hollischuang";
        }
    }
    

    以上代码的Model3中,只有一个成员变量即isSuccess,三个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,另外一个是作者自己增加的一个符合getter命名规范的方法。

    以上代码输出结果:

    Serializable Result With fastjson :{"hollis":"hollischuang","success":true}
    Serializable Result With Gson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true,"hollis":"hollischuang"}
    

    在fastjson和jackson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含hollis值。而Gson中只有isSuccess字段。

    我们可以得出结论:fastjson和jackson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法,得到getHollis和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性hollis和success的值。直接序列化成json:{“hollis”:“hollischuang”,“success”:true}

    但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:{“isSuccess”:true}

    可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。

    前面提到的关于对getHollis的序列化只是为了说明fastjson、jackson和Gson之间的序列化策略的不同,我们暂且把他放到一边,我们把他从Model3中删除后,重新执行下以上代码,得到结果:

    Serializable Result With fastjson :{"success":true}
    Serializable Result With Gson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true}
    

    现在,不同的序列化框架得到的json内容并不相同,如果对于同一个对象,我使用fastjson进行序列化,再使用Gson反序列化会发生什么?

    public class BooleanMainTest {
        public static void main(String[] args) throws IOException {
            Model3 model3 = new Model3();
            model3.setSuccess(true);
            Gson gson =new Gson();
            System.out.println(gson.fromJson(JSON.toJSONString(model3),Model3.class));
        }
    }
    
    
    class Model3 implements Serializable {
        private static final long serialVersionUID = 1836697963736227954L;
        private boolean isSuccess;
        public boolean isSuccess() {
            return isSuccess;
        }
        public void setSuccess(boolean success) {
            isSuccess = success;
        }
        @Override
        public String toString() {
            return new StringJoiner(", ", Model3.class.getSimpleName() + "[", "]")
                .add("isSuccess=" + isSuccess)
                .toString();
        }
    }
    

    以上代码,输出结果:

    Model3[isSuccess=false]
    

    这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把model对象序列化城字符串后内容为{"success":true}

    根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Model类中的success属性,但是Model类中只有isSuccess属性,所以,最终反序列化后的Model类的对象中,isSuccess则会使用默认值false。

    但是,一旦以上代码发生在生产环境,这绝对是一个致命的问题。

    所以,作为开发者,我们应该想办法尽量避免这种问题的发生,对于POJO的设计者来说,只需要做简单的一件事就可以解决这个问题了,那就是把isSuccess改为success。这样,该类里面的成员变量时success,getter方法是isSuccess,这是完全符合JavaBeans规范的。无论哪种序列化框架,执行结果都一样。就从源头避免了这个问题。

    引用以下R大关于阿里巴巴Java开发手册这条规定的评价(https://www.zhihu.com/question/55642203):

    -w665

    所以,在定义POJO中的布尔类型的变量时,不要使用isSuccess这种形式,而要直接使用success!

    Boolean还是boolean?

    前面我们介绍完了在success和isSuccess之间如何选择,那么排除错误答案后,备选项还剩下:

    boolean success
    Boolean success
    

    那么,到底应该是用Boolean还是boolean来给定一个布尔类型的变量呢?

    我们知道,boolean是基本数据类型,而Boolean是包装类型。关于基本数据类型和包装类之间的关系和区别请参考一文读懂什么是Java中的自动拆装箱

    那么,在定义一个成员变量的时候到底是使用包装类型更好还是使用基本数据类型呢?

    我们来看一段简单的代码

     /**
     * @author Hollis
     */
    public class BooleanMainTest {
        public static void main(String[] args) {
            Model model1 = new Model();
            System.out.println("default model : " + model1);
        }
    }
    
    class Model {
        /**
         * 定一个Boolean类型的success成员变量
         */
        private Boolean success;
        /**
         * 定一个boolean类型的failure成员变量
         */
        private boolean failure;
    
        /**
         * 覆盖toString方法,使用Java 8 的StringJoiner
         */
        @Override
        public String toString() {
            return new StringJoiner(", ", Model.class.getSimpleName() + "[", "]")
                .add("success=" + success)
                .add("failure=" + failure)
                .toString();
        }
    }
    

    以上代码输出结果为:

    default model : Model[success=null, failure=false]
    

    可以看到,当我们没有设置Model对象的字段的值的时候,Boolean类型的变量会设置默认值为null,而boolean类型的变量会设置默认值为false

    即对象的默认值是null,boolean基本数据类型的默认值是false

    在阿里巴巴Java开发手册中,对于POJO中如何选择变量的类型也有着一些规定:

    这里建议我们使用包装类型,原因是什么呢?

    举一个扣费的例子,我们做一个扣费系统,扣费时需要从外部的定价系统中读取一个费率的值,我们预期该接口的返回值中会包含一个浮点型的费率字段。当我们取到这个值得时候就使用公式:金额*费率=费用 进行计算,计算结果进行划扣。

    如果由于计费系统异常,他可能会返回个默认值,如果这个字段是Double类型的话,该默认值为null,如果该字段是double类型的话,该默认值为0.0。

    如果扣费系统对于该费率返回值没做特殊处理的话,拿到null值进行计算会直接报错,阻断程序。拿到0.0可能就直接进行计算,得出接口为0后进行扣费了。这种异常情况就无法被感知。

    这种使用包装类型定义变量的方式,通过异常来阻断程序,进而可以被识别到这种线上问题。如果使用基本数据类型的话,系统可能不会报错,进而认为无异常。

    以上,就是建议在POJO和RPC的返回值中使用包装类型的原因。

    但是关于这一点,作者之前也有过不同的看法:对于布尔类型的变量,我认为可以和其他类型区分开来,作者并不认为使用null进而导致NPE是一种最好的实践。因为布尔类型只有true/false两种值,我们完全可以和外部调用方约定好当返回值为false时的明确语义。

    后来,作者单独和《阿里巴巴Java开发手册》、《码出高效》的作者——孤尽 单独1V1(qing) Battle(jiao)了一下。最终达成共识,还是尽量使用包装类型

    但是,作者还是想强调一个我的观点,尽量避免在你的代码中出现不确定的null值。

    null何罪之有?

    关于null值的使用,我在使用Optional避免NullPointerException9 Things about Null in Java等文中就介绍过。

    null是很模棱两可的,很多时候会导致令人疑惑的的错误,很难去判断返回一个null代表着什么意思。

    图灵奖得主Tony Hoare 曾经公开表达过null是一个糟糕的设计。

    我把 null 引用称为自己的十亿美元错误。它的发明是在1965 年,那时我用一个面向对象语言( ALGOL W )设计了第一个全面的引用类型系统。我的目的是确保所有引用的使用都是绝对安全的,编译器会自动进行检查。但是我未能抵御住诱惑,加入了Null引用,仅仅是因为实现起来非常容易。它导致了数不清的错误、漏洞和系统崩溃,可能在之后 40 年中造成了十亿美元的损失。

    当我们在设计一个接口的时候,对于接口的返回值的定义,尽量避免使用Boolean类型来定义。大多数情况下,别人使用我们的接口返回值时可能用if(response.isSuccess){}else{}的方式,如果我们由于忽略没有设置success字段的值,就可能导致NPE(java.lang.NullPointerException),这明显是我们不希望看到的。

    所以,当我们要定义一个布尔类型的成员变量时,尽量选择boolean,而不是Boolean。当然,编程中并没有绝对。

    总结

    本文围绕布尔类型的变量定义的类型和命名展开了介绍,最终我们可以得出结论,在定义一个布尔类型的变量,尤其是一个给外部提供的接口返回值时,要使用success来命名,阿里巴巴Java开发手册建议使用封装类来定义POJO和RPC返回值中的变量。但是这不意味着可以随意的使用null,我们还是要尽量避免出现对null的处理的。

    更多《阿里巴巴Java开发手册》相关解读,欢淫关注我的公众号阅读。
    wechat

    展开全文
  • 在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的...一般情况下,我们可以以下四种方式来定义一个布尔类型的成员变量...

    在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的。

    关于这个”本次请求是否成功”的字段的定义,其实是有很多种讲究和坑的,稍有不慎就会掉入坑里,作者在很久之前就遇到过类似的问题,本文就来围绕这个简单分析一下。到底该如何定一个布尔类型的成员变量。

    一般情况下,我们可以有以下四种方式来定义一个布尔类型的成员变量:

    boolean success
    boolean isSuccess
    Boolean success
    Boolean isSuccess

    以上四种定义形式,你日常开发中最常用的是哪种呢?到底哪一种才是正确的使用姿势呢?

    通过观察我们可以发现,前两种和后两种的主要区别是变量的类型不同,前者使用的是boolean,后者使用的是Boolean。

    另外,第一种和第三种在定义变量的时候,变量命名是success,而另外两种使用isSuccess来命名的。

    首先,我们来分析一下,到底应该是用success来命名,还是使用isSuccess更好一点。


    success 还是 isSucces

    到底应该是用success还是isSuccess来给变量命名呢?从语义上面来讲,两种命名方式都可以讲的通,并且也都没有歧义。那么还有什么原则可以参考来让我们做选择呢。

     

    在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:


    那么,为什么会有这样的规定呢?我们看一下POJO中布尔类型变量不同的命名有什么区别吧。

    class Model1  {
       private Boolean isSuccess;
       public void setSuccess(Boolean success) {
           isSuccess = success;
       }
       public Boolean getSuccess() {
           return isSuccess;
       }
    }
    
    class Model2 {
       private Boolean success;
       public Boolean getSuccess() {
           return success;
       }
       public void setSuccess(Boolean success) {
           this.success = success;
       }
    }
    
    class Model3 {
       private boolean isSuccess;
       public boolean isSuccess() {
           return isSuccess;
       }
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
    }
    
    class Model4 {
       private boolean success;
       public boolean isSuccess() {
           return success;
       }
       public void setSuccess(boolean success) {
           this.success = success;
       }
    }

    以上代码的setter/getter是使用Intellij IDEA自动生成的,仔细观察以上代码,你会发现以下规律:

    • 基本类型自动生成的getter和setter方法,名称都是isXXX()setXXX()形式的。

    • 包装类型自动生成的getter和setter方法,名称都是getXXX()setXXX()形式的。

     

    既然,我们已经达成一致共识使用基本类型boolean来定义成员变量了,那么我们再来具体看下Model3和Model4中的setter/getter有何区别。

    我们可以发现,虽然Model3和Model4中的成员变量的名称不同,一个是success,另外一个是isSuccess,但是他们自动生成的getter和setter方法名称都是isSuccesssetSuccess

    Java Bean中关于setter/getter的规范

    关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specification规定,如果是普通的参数,命名为propertyName,需要通过以下方式定义其setter/getter:

    public <PropertyType> get<PropertyName>();
    public void set<PropertyName>(<PropertyType> a);

    但是,布尔类型的变量propertyName则是另外一套命名原则的:

    public boolean is<PropertyName>();
    public void set<PropertyName>(boolean m);

    通过对照这份JavaBeans规范,我们发现,在Model4中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。

    那这样做会带来什么问题呢。

    在一般情况下,其实是没有影响的。但是有一种特殊情况就会有问题,那就是发生序列化的时候。

    序列化带来的影响

    关于序列化和反序列化请参考Java对象的序列化与反序列化。我们这里拿比较常用的JSON序列化来举例,看看常用的fastJson、jackson和Gson之间有何区别:

    /**
    * @author Hollis
    */
    public class BooleanMainTest {
    
       public static void main(String[] args) throws IOException {
           //定一个Model3类型
           Model3 model3 = new Model3();
           model3.setSuccess(true);
    
           //使用fastjson(1.2.16)序列化model3成字符串并输出
           System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model3));
    
           //使用Gson(2.8.5)序列化model3成字符串并输出
           Gson gson =new Gson();
           System.out.println("Serializable Result With Gson :"+gson.toJson(model3));
    
           //使用jackson(2.9.7)序列化model3成字符串并输出
           ObjectMapper om = new ObjectMapper();
           System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));
       }
    }
    
    class Model3 implements Serializable {
    
       private static final long serialVersionUID = 1836697963736227954L;
       private boolean isSuccess;
       public boolean isSuccess() {
           return isSuccess;
       }
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
       public String getHollis(){
           return "hollischuang";
       }
    }

    以上代码的Model3中,只有一个成员变量即isSuccess,三个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,另外一个是作者自己增加的一个符合getter命名规范的方法。

    以上代码输出结果:

    Serializable Result With fastjson :{"hollis":"hollischuang","success":true}
    Serializable Result With Gson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true,"hollis":"hollischuang"}

    在fastjson和jackson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含hollis值。而Gson中只有isSuccess字段。

    我们可以得出结论:fastjson和jackson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法,得到getHollis和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性hollis和success的值。直接序列化成json:

    {“hollis”:”hollischuang”,”success”:true}

    但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:

    {“isSuccess”:true}

    可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。

    前面提到的关于对getHollis的序列化只是为了说明fastjson、jackson和Gson之间的序列化策略的不同,我们暂且把他放到一边,我们把他从Model3中删除后,重新执行下以上代码,得到结果:

    Serializable Result With fastjson :{"success":true}
    Serializable Result WithGson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true}

    现在,不同的序列化框架得到的json内容并不相同,如果对于同一个对象,我使用fastjson进行序列化,再使用Gson反序列化会发生什么?

    public class BooleanMainTest {
       public static void main(String[] args) throws IOException {
           Model3 model3 = new Model3();
           model3.setSuccess(true);
           Gson gson =new Gson();
           System.out.println(gson.fromJson(JSON.toJSONString(model3),Model3.class));
       }
    }
    
    class Model3 implements Serializable {
       private static final long serialVersionUID = 1836697963736227954L;
       private boolean isSuccess;
       public boolean isSuccess() {
           return isSuccess;
       }
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
       @Override
       public String toString() {
           return new StringJoiner(", ", Model3.class.getSimpleName() + "[","]")
               .add("isSuccess=" + isSuccess)
               .toString();
       }
    }

    以上代码,输出结果:

    Model3[isSuccess=false]

    这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把model对象序列化城字符串后内容为{"success":true}

    根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Model类中的success属性,但是Model类中只有isSuccess属性,所以,最终反序列化后的Model类的对象中,isSuccess则会使用默认值false。

    但是,一旦以上代码发生在生产环境,这绝对是一个致命的问题。

    所以,作为开发者,我们应该想办法尽量避免这种问题的发生,对于POJO的设计者来说,只需要做简单的一件事就可以解决这个问题了,那就是把isSuccess改为success。

    这样,该类里面的成员变量时success,getter方法是isSuccess,这是完全符合JavaBeans规范的。无论哪种序列化框架,执行结果都一样。就从源头避免了这个问题。

    引用一下R大关于阿里巴巴Java开发手册中这条规定的评价

    (https://www.zhihu.com/question/55642203):

    所以,在定义POJO中的布尔类型的变量时,不要使用isSuccess这种形式,而要直接使用success!

    Boolean还是boolean?

    前面我们介绍完了在success和isSuccess之间如何选择,那么排除错误答案后,备选项还剩下:

    boolean success
    Boolean success

    那么,到底应该是用Boolean还是boolean来给定一个布尔类型的变量呢?

    我们知道,boolean是基本数据类型,而Boolean是包装类型。关于基本数据类型和包装类之间的关系和区别请参考一文读懂什么是Java中的自动拆装箱

    那么,在定义一个成员变量的时候到底是使用包装类型更好还是使用基本数据类型呢?

    我们来看一段简单的代码

    /**
    * @author Hollis
    */
    public class BooleanMainTest {
       public static void main(String[] args) {
           Model model1 = new Model();
           System.out.println("default model : " + model1);
       }
    }
    
    class Model {
       /**
        * 定一个Boolean类型的success成员变量
        */
       private Boolean success;
       /**
        * 定一个boolean类型的failure成员变量
        */
       private boolean failure;
    
       /**
        * 覆盖toString方法,使用Java 8 的StringJoiner
        */
       @Override
       public String toString() {
           return new StringJoiner(", ", Model.class.getSimpleName() + "[","]")
               .add("success=" + success)
               .add("failure=" + failure)
               .toString();
       }
    }

    以上代码输出结果为:

    default model : Model[success=null, failure=false]

    可以看到,当我们没有设置Model对象的字段的值的时候,Boolean类型的变量会设置默认值为null,而boolean类型的变量会设置默认值为false

    即对象的默认值是null,boolean基本数据类型的默认值是false

    在阿里巴巴Java开发手册中,对于POJO中如何选择变量的类型也有着一些规定:

    这里建议我们使用包装类型,原因是什么呢?

     

    举一个扣费的例子,我们做一个扣费系统,扣费时需要从外部的定价系统中读取一个费率的值,我们预期该接口的返回值中会包含一个浮点型的费率字段。当我们取到这个值得时候就使用公式:金额*费率=费用 进行计算,计算结果进行划扣。

     

    如果由于计费系统异常,他可能会返回个默认值,如果这个字段是Double类型的话,该默认值为null,如果该字段是double类型的话,该默认值为0.0。

     

    如果扣费系统对于该费率返回值没做特殊处理的话,拿到null值进行计算会直接报错,阻断程序。拿到0.0可能就直接进行计算,得出接口为0后进行扣费了。这种异常情况就无法被感知。

     

    这种使用包装类型定义变量的方式,通过异常来阻断程序,进而可以被识别到这种线上问题。如果使用基本数据类型的话,系统可能不会报错,进而认为无异常。

     

    以上,就是建议在POJO和RPC的返回值中使用包装类型的原因。

     

    在之前那篇文章的解析中,作者的观点是,对于布尔类型的变量,我认为可以和其他类型区分开来,作者并不认为使用null进而导致NPE是一种最好的实践。因为布尔类型只有true/false两种值,我们完全可以和外部调用方约定好当返回值为false时的明确语义。

     

    所以之前建议大家使用boolean来定义success变量,后来有读者评论或者私下和我沟通,关于这部分内容又有了一些新的思考。

     

    后来,作者单独和《阿里巴巴Java开发手册》、《码出高效》的作者——孤尽 单独1V1(qing) Battle(jiao)了一下。最终达成共识,还是尽量使用包装类型。

     

    但是,作者还是想强调一个我的观点,尽量避免在你的代码中出现不确定的null值。

     

    null何罪之有?

    null是很模棱两可的,很多时候会导致令人疑惑的错误,很难去判断返回一个null代表着什么意思。

    图灵奖得主Tony Hoare 曾经公开表达过null是一个糟糕的设计。

    我把 null 引用称为自己的十亿美元错误。它的发明是在1965 年,那时我用一个面向对象语言( ALGOL W )设计了第一个全面的引用类型系统。我的目的是确保所有引用的使用都是绝对安全的,编译器会自动进行检查。但是我未能抵御住诱惑,加入了Null引用,仅仅是因为实现起来非常容易。它导致了数不清的错误、漏洞和系统崩溃,可能在之后 40 年中造成了十亿美元的损失。

     

    当我们在设计一个接口的时候,对于接口的返回值的定义,尽量避免使用Boolean类型来定义。大多数情况下,别人使用我们的接口返回值时可能用if(response.isSuccess){}else{}的方式,如果我们由于忽略没有设置success字段的值,就可能导致NPE,这明显是我们不希望看到的。

     

    当然,编程中并没有绝对。两种方式是两种思维方式,多提供一种思路,供读者们在日常开发中自行选择。


    总结:

    本文围绕布尔类型的变量定义的类型和命名展开了介绍,最终我们可以得出结论,在定义一个布尔类型的变量,尤其是一个给外部提供的接口返回值时,要使用success来命名,阿里巴巴Java开发手册建议使用封装类来定义POJO和RPC返回值中的变量。但是这不意味着可以随意的使用null,我们还是要尽量避免出现对null的处理的。

     

    好啦,以上就是关于POJO中布尔类型变量的正确定义姿势。你用对了么?

     

    展开全文
  • 在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的...一般情况下,我们可以以下四种方式来定义一个布尔类型的成员变量...

    在日常开发中,我们会经常要在类中定义布尔类型的变量,比如在给外部系统提供一个RPC接口的时候,我们一般会定义一个字段表示本次请求是否成功的。

    关于这个”本次请求是否成功”的字段的定义,其实是有很多种讲究和坑的,稍有不慎就会掉入坑里,作者在很久之前就遇到过类似的问题,本文就来围绕这个简单分析一下。到底该如何定一个布尔类型的成员变量。

    一般情况下,我们可以有以下四种方式来定义一个布尔类型的成员变量:

    boolean success
    boolean isSuccess
    Boolean success
    Boolean isSuccess

    以上四种定义形式,你日常开发中最常用的是哪种呢?到底哪一种才是正确的使用姿势呢?

    通过观察我们可以发现,前两种和后两种的主要区别是变量的类型不同,前者使用的是boolean,后者使用的是Boolean。

    另外,第一种和第三种在定义变量的时候,变量命名是success,而另外两种使用isSuccess来命名的。

    首先,我们来分析一下,到底应该是用success来命名,还是使用isSuccess更好一点。

     

    success 还是 isSuccess

    到底应该是用success还是isSuccess来给变量命名呢?从语义上面来讲,两种命名方式都可以讲的通,并且也都没有歧义。那么还有什么原则可以参考来让我们做选择呢。

    在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:


    那么,为什么会有这样的规定呢?我们看一下POJO中布尔类型变量不同的命名有什么区别吧。

    class Model1  {
       private Boolean isSuccess;
       public void setSuccess(Boolean success) {
           isSuccess = success;
       }
       public Boolean getSuccess() {
           return isSuccess;
       }
    }
    
    class Model2 {
       private Boolean success;
       public Boolean getSuccess() {
           return success;
       }
       public void setSuccess(Boolean success) {
           this.success = success;
       }
    }
    
    class Model3 {
       private boolean isSuccess;
       public boolean isSuccess() {
           return isSuccess;
       }
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
    }
    
    class Model4 {
       private boolean success;
       public boolean isSuccess() {
           return success;
       }
       public void setSuccess(boolean success) {
           this.success = success;
       }
    }

    以上代码的setter/getter是使用Intellij IDEA自动生成的,仔细观察以上代码,你会发现以下规律:

    • 基本类型自动生成的getter和setter方法,名称都是isXXX()setXXX()形式的。

    • 包装类型自动生成的getter和setter方法,名称都是getXXX()setXXX()形式的。

    既然,我们已经达成一致共识使用基本类型boolean来定义成员变量了,那么我们再来具体看下Model3和Model4中的setter/getter有何区别。

    我们可以发现,虽然Model3和Model4中的成员变量的名称不同,一个是success,另外一个是isSuccess,但是他们自动生成的getter和setter方法名称都是isSuccesssetSuccess

    Java Bean中关于setter/getter的规范

    关于Java Bean中的getter/setter方法的定义其实是有明确的规定的,根据JavaBeans(TM) Specification规定,如果是普通的参数,命名为propertyName,需要通过以下方式定义其setter/getter:

    public <PropertyType> get<PropertyName>();
    public void set<PropertyName>(<PropertyType> a);

    但是,布尔类型的变量propertyName则是另外一套命名原则的:

    public boolean is<PropertyName>();
    public void set<PropertyName>(boolean m);

     

    通过对照这份JavaBeans规范,我们发现,在Model4中,变量名为isSuccess,如果严格按照规范定义的话,他的getter方法应该叫isIsSuccess。但是很多IDE都会默认生成为isSuccess。

    那这样做会带来什么问题呢。

    在一般情况下,其实是没有影响的。但是有一种特殊情况就会有问题,那就是发生序列化的时候。

    序列化带来的影响

    关于序列化和反序列化请参考Java对象的序列化与反序列化。我们这里拿比较常用的JSON序列化来举例,看看常用的fastJson、jackson和Gson之间有何区别:

    /**
    * @author Hollis
    */
    public class BooleanMainTest {
    
       public static void main(String[] args) throws IOException {
           //定一个Model3类型
           Model3 model3 = new Model3();
           model3.setSuccess(true);
    
           //使用fastjson(1.2.16)序列化model3成字符串并输出
           System.out.println("Serializable Result With fastjson :" + JSON.toJSONString(model3));
    
           //使用Gson(2.8.5)序列化model3成字符串并输出
           Gson gson = new Gson();
           System.out.println("Serializable Result With Gson :"+gson.toJson(model3));
    
           //使用jackson(2.9.7)序列化model3成字符串并输出
           ObjectMapper om = new ObjectMapper();
           System.out.println("Serializable Result With jackson :" +om.writeValueAsString(model3));
       }
    }
    
    class Model3 implements Serializable {
    
       private static final long serialVersionUID = 1836697963736227954L;
       private boolean isSuccess;
    
       public boolean isSuccess() {
           return isSuccess;
       }
    
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
    
       public String getHollis(){
           return "hollischuang";
       }
    }

    以上代码的Model3中,只有一个成员变量即isSuccess,三个方法,分别是IDE帮我们自动生成的isSuccess和setSuccess,另外一个是作者自己增加的一个符合getter命名规范的方法。

    以上代码输出结果:

    Serializable Result With fastjson :{"hollis":"hollischuang","success":true}
    Serializable Result With Gson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true,"hollis":"hollischuang"}

    在fastjson和jackson的结果中,原来类中的isSuccess字段被序列化成success,并且其中还包含hollis值。而Gson中只有isSuccess字段。

    我们可以得出结论:fastjson和jackson在把对象序列化成json字符串的时候,是通过反射遍历出该类中的所有getter方法,得到getHollis和isSuccess,然后根据JavaBeans规则,他会认为这是两个属性hollis和success的值。直接序列化成json:

    {“hollis”:”hollischuang”,”success”:true}

    但是Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json:

    {“isSuccess”:true}

    可以看到,由于不同的序列化工具,在进行序列化的时候使用到的策略是不一样的,所以,对于同一个类的同一个对象的序列化结果可能是不同的。

    前面提到的关于对getHollis的序列化只是为了说明fastjson、jackson和Gson之间的序列化策略的不同,我们暂且把他放到一边,我们把他从Model3中删除后,重新执行下以上代码,得到结果:

    Serializable Result With fastjson :{"success":true}
    Serializable Result WithGson :{"isSuccess":true}
    Serializable Result With jackson :{"success":true}

    现在,不同的序列化框架得到的json内容并不相同,如果对于同一个对象,我使用fastjson进行序列化,再使用Gson反序列化会发生什么?

    public class BooleanMainTest {
       public static void main(String[] args) throws IOException {
           Model3 model3 = new Model3();
           model3.setSuccess(true);
           Gson gson = new Gson();
           System.out.println(gson.fromJson(JSON.toJSONString(model3),Model3.class));
       }
    }
    
    class Model3 implements Serializable {
       private static final long serialVersionUID = 1836697963736227954L;
       private boolean isSuccess;
       public boolean isSuccess() {
           return isSuccess;
       }
       public void setSuccess(boolean success) {
           isSuccess = success;
       }
       @Override
       public String toString() {
           return new StringJoiner(", ", Model3.class.getSimpleName() + "[","]")
               .add("isSuccess=" + isSuccess)
               .toString();
       }
    }

    以上代码,输出结果:

    Model3[isSuccess=false]

    这和我们预期的结果完全相反,原因是因为JSON框架通过扫描所有的getter后发现有一个isSuccess方法,然后根据JavaBeans的规范,解析出变量名为success,把model对象序列化成字符串后内容为{"success":true}

    根据{"success":true}这个json串,Gson框架在通过解析后,通过反射寻找Model类中的success属性,但是Model类中只有isSuccess属性,所以,最终反序列化后的Model类的对象中,isSuccess则会使用默认值false。

    但是,一旦以上代码发生在生产环境,这绝对是一个致命的问题。

    所以,作为开发者,我们应该想办法尽量避免这种问题的发生,对于POJO的设计者来说,只需要做简单的一件事就可以解决这个问题了,那就是把isSuccess改为success。

    这样,该类里面的成员变量时success,getter方法是isSuccess,这是完全符合JavaBeans规范的。无论哪种序列化框架,执行结果都一样。就从源头避免了这个问题。

    引用一下R大关于阿里巴巴Java开发手册中这条规定的评价

    (https://www.zhihu.com/question/55642203):

    所以,在定义POJO中的布尔类型的变量时,不要使用isSuccess这种形式,而要直接使用success!

     

    Boolean还是boolean?

    前面我们介绍完了在success和isSuccess之间如何选择,那么排除错误答案后,备选项还剩下:

    boolean success
    Boolean success

    那么,到底应该是用Boolean还是boolean来给定一个布尔类型的变量呢?

    我们知道,boolean是基本数据类型,而Boolean是包装类型。关于基本数据类型和包装类之间的关系和区别请参考一文读懂什么是Java中的自动拆装箱

    那么,在定义一个成员变量的时候到底是使用包装类型更好还是使用基本数据类型呢?

    我们来看一段简单的代码

    /**
    * @author Hollis
    */
    public class BooleanMainTest {
       public static void main(String[] args) {
           Model model1 = new Model();
           System.out.println("default model : " + model1);
       }
    }
    
    class Model {
       /**
        * 定一个Boolean类型的success成员变量
        */
       private Boolean success;
       /**
        * 定一个boolean类型的failure成员变量
        */
       private boolean failure;
    
       /**
        * 覆盖toString方法,使用Java 8 的StringJoiner
        */
       @Override
       public String toString() {
           return new StringJoiner(", ", Model.class.getSimpleName() + "[","]")
               .add("success=" + success)
               .add("failure=" + failure)
               .toString();
       }
    }

    以上代码输出结果为:

    default model : Model[success=null, failure=false]

    可以看到,当我们没有设置Model对象的字段的值的时候,Boolean类型的变量会设置默认值为null,而boolean类型的变量会设置默认值为false

    即对象的默认值是null,boolean基本数据类型的默认值是false

    在阿里巴巴Java开发手册中,对于POJO中如何选择变量的类型也有着一些规定:

    这里建议我们使用包装类型,原因是什么呢?

    举一个扣费的例子,我们做一个扣费系统,扣费时需要从外部的定价系统中读取一个费率的值,我们预期该接口的返回值中会包含一个浮点型的费率字段。当我们取到这个值得时候就使用公式:金额*费率=费用 进行计算,计算结果进行划扣。

    如果由于计费系统异常,他可能会返回个默认值,如果这个字段是Double类型的话,该默认值为null,如果该字段是double类型的话,该默认值为0.0。

    如果扣费系统对于该费率返回值没做特殊处理的话,拿到null值进行计算会直接报错,阻断程序。拿到0.0可能就直接进行计算,得出接口为0后进行扣费了。这种异常情况就无法被感知。

    这种使用包装类型定义变量的方式,通过异常来阻断程序,进而可以被识别到这种线上问题。如果使用基本数据类型的话,系统可能不会报错,进而认为无异常。

    以上,就是建议在POJO和RPC的返回值中使用包装类型的原因。

    在之前那篇文章的解析中,作者的观点是,对于布尔类型的变量,我认为可以和其他类型区分开来,作者并不认为使用null进而导致NPE是一种最好的实践。因为布尔类型只有true/false两种值,我们完全可以和外部调用方约定好当返回值为false时的明确语义。

    所以之前建议大家使用boolean来定义success变量,后来有读者评论或者私下和我沟通,关于这部分内容又有了一些新的思考。

    后来,作者单独和《阿里巴巴Java开发手册》、《码出高效》的作者——孤尽 单独1V1(qing) Battle(jiao)了一下。最终达成共识,还是尽量使用包装类型

    但是,作者还是想强调一个我的观点,尽量避免在你的代码中出现不确定的null值。

     

    null何罪之有?

    null是很模棱两可的,很多时候会导致令人疑惑的错误,很难去判断返回一个null代表着什么意思。

    图灵奖得主Tony Hoare 曾经公开表达过null是一个糟糕的设计。

    我把 null 引用称为自己的十亿美元错误。它的发明是在1965 年,那时我用一个面向对象语言( ALGOL W )设计了第一个全面的引用类型系统。我的目的是确保所有引用的使用都是绝对安全的,编译器会自动进行检查。但是我未能抵御住诱惑,加入了Null引用,仅仅是因为实现起来非常容易。它导致了数不清的错误、漏洞和系统崩溃,可能在之后 40 年中造成了十亿美元的损失。

    当我们在设计一个接口的时候,对于接口的返回值的定义,尽量避免使用Boolean类型来定义。大多数情况下,别人使用我们的接口返回值时可能用if(response.isSuccess){}else{}的方式,如果我们由于忽略没有设置success字段的值,就可能导致NPE,这明显是我们不希望看到的。

    当然,编程中并没有绝对。两种方式是两种思维方式,多提供一种思路,供读者们在日常开发中自行选择。

     

    总结

    本文围绕布尔类型的变量定义的类型和命名展开了介绍,最终我们可以得出结论,在定义一个布尔类型的变量,尤其是一个给外部提供的接口返回值时,要使用success来命名,阿里巴巴Java开发手册建议使用包装类来定义POJO和RPC返回值中的变量。但是这不意味着可以随意的使用null,我们还是要尽量避免出现对null的处理的。

    好啦,以上就是关于POJO中布尔类型变量的正确定义姿势。你用对了么?

    展开全文
  • 在引用这个变量是我们可以直接使用$后面跟上变量的名字 比如: $FILEPATH 还可以 : ${FILEPATH} 使用${}这种方式的好处是可以方便的实现两个变量的连接,同时看着也比较清楚。 ...

    tips:使用eval

    例如:

    [plain] view plain copy
    1. #!/bin/bash  
    2. name=yushuang  
    3. var=name  
    4. # 要获取到yushuang  
    5. res=`eval echo '$'"$var"`  
    6. echo $res  


    说明:

    第一步: "$var"  -->name

    第二步: echo '$'"$var" -->$name

    第三步: `eval $name` -->yushuang



    一.基础

    我们定义一个变量(等号两边不能有空格)

    FILEPATH=/var/home/sss
    FILEFILENAME=test001


    在引用这个变量是我们可以直接使用$后面跟上变量的名字

    比如:       $FILEPATH
    还可以 :  ${FILEPATH}


    使用${}这种方式的好处是可以方便的实现两个变量的连接,同时看着也比较清楚。

    ${FILEPATH}/${FILEFILENAME}

    这样便可以表示这个文件的全路径了

    ---------------------------------------------

    二. 此外有时我们会看到

    $1,$2这种形式,这代表执行shell时,传递进来的参数

    -------------------------------------------


    三. 此外我们还会看到下面的这些形式

    1.如果变量米有赋值或为空,使用value的值

    ${variable:-value}


    2.如果变量米有赋值或为空,使用value的值,并把变量赋值为value

    ${variable:=value}


    3.检验变量是否为空

    ${variable:?}

    ------------------------------------------

    以下是一些不常用的

    --------------------------------------------

    $0  shell的命令本身(包括完整路径)  
    $1到$9 数字表示shell 的第几个参数   
    $# 传递到脚本的参数个数  
    $* 以一个单字符串显示所有向脚本传递的参数  
    $$ 脚本运行的ID号  
    $! 后台运行的最后一个进程的ID号  
    $@ 与$*相同。  
    $- 显示shell使用的当前选项。  
    $? 显示最后命令的执行状况。0表示没有错误。 


    展开全文
  • 则用镜像法计算球外的电势分布时,镜像电荷有: 【单选题】以下选项中不符合 Python 语言变量命名规则的是( )。 【判断题】服务企业不存在物流问题。 【单选题】下面的双重循环中的内循环体将一共会被执行( )次 for(i=...
  • MySQL5.6 选项变量整理

    万次阅读 2013-12-30 14:10:34
    MySQL5.6 选项变量整理  (2013-04-01 18:10:00) 转载▼ 标签:  mysql5.6配置参数整理 分类: MySQL  --allow-suspicious-udfs 这个选项控制是否用户定义函数只有一个xxx符号用于主函数加载...
  • 2.变量名【字母,数字,下划线_,不能包含特殊符号,不能以数字开头】 3.如变量名已经存在,同名变量会被覆盖   调用变量 $名称 a=1 echo ${a}RMB 相当于(1+2)*2 有歧义就加个{}   10、SHEEL 弱类型的...
  • 在 mixin 中定义的所有变量都是可见的,并且可以在调用者的作用范围中使用 (除非调用者用相同的名称定义它自己的变量)。 .mixin(){ @width:100%; @height:200px; } .caller{ .mixin(); width: @width; height:...
  • 《MySQL 入门教程》第 17 篇 MySQL 变量

    千次阅读 2020-08-03 17:46:28
    MySQL 中的变量可以分为系统全局变量和会话变量、用户变量以及局部变量。本篇介绍这些变量的设置和使用,包括使用SHOW VARIABLES和SELECT 语句查看系统变量,使用SET命令设置系统变量和用户变量,以及通过用户变量...
  • GCC编译选项参数

    千次阅读 2020-08-03 18:38:19
    GCC 编译选项参数 1 常用选项 2 预处理器选项 -includefile 在处理常规输入文件之前,首先处理文件file,其结果是,文件file的内容先得到编译.命令行上任何-D'和-U’选项永远在-includefile'之前处理,无论他们在命令行...
  • C51:Keil c51指针变量

    千次阅读 2015-06-28 11:44:53
    要在程序中使用变量必须先用标识符作为变量名,并指出所用的数据类型和存储模式,这样编译系统才 能为变量分配相应的存储空间。定义一个变量的格式如下:   [存储种类] 数据类型 [存储器类型] 变量名表 ...
  • Shell script 传参数处理(默认变量

    千次阅读 2013-10-25 19:49:12
    与位置变量不同,此选项参数可超过9个 3. $$ 脚本运行的当前进程ID号 4. $! 后台运行的最后一个进程的进程ID号 5. $@ 与$#相同,但是使用时加引号,并在引号中返回每个参数 6. $- 显示shell使用的当前选项,与set...
  • Vue组件中data选项为什么必须是函数

    千次阅读 2017-10-28 10:55:25
    构造 Vue 实例时传入的各种选项大多数都可以在组件里使用。只有一个例外:data 必须是函数。实际上,如果你这么做: Vue.component('my-component', { template: '<span>{{ message }}</span>', data: { message...
  • 以下所有操作均在Centos6.10上进行 今儿在一台新虚拟机上安装pip之后,用pip安装包,需要root权限,但执行sudo pip就提示command not found ...可以使用printenv这个命令,检查当前的PATH变量...
  • ahk变量与内置变量

    千次阅读 2017-02-09 10:14:35
    然而, 只包含数字 (可以含有小数点) 的变量进行数学运算或比较时, 会被自动转换为数值. (为了提高性能, 在内部会对数字进行缓存以避免与字符串之间的转换.) 变量的作用域和声明: 除了函数中的 局部变量, 其他...
  • Linux中shell变量说明

    千次阅读 2015-08-11 12:24:04
    shell变量可以保存诸如路径名、文件名或者一个数字这样的变量名。shell将其中任何设置都看做文本字符串。 有两种变量,本地和环境。严格地说可以有4种,但其余两种是只读的,可以认为是特殊变量,它用
  • makefile 隐含变量

    千次阅读 2013-05-03 09:23:38
    隐含变量 内嵌隐含规则的命令中, 所使用的变量都是预定义的变量。我们将这些变量称为“隐含变量”。这些变量允许对它进行修改:在...当然,也可以使用“-R”或“--no builtin-variables”选项来取消所有的隐含变量(同时
  • shell的本地变量和环境变量

    千次阅读 2015-09-24 16:08:31
    shell变量可以保存诸如路径名、文件名或者一个数字这样的变量名。shell将其中任何设置都看做文本字符串。 有两种变量,本地和环境。严格地说可以有4种,但其余两种是只读的,可以认为是特殊变量,它用于向shell脚本...
  • gcc 编译选项

    千次阅读 2017-05-31 11:23:54
    提供了大量的警告选项,对代码中可能存在的问题提出警 告,通常可以使用-Wall来开启以下警告:  -Waddress -Warray-bounds (only with -O2) -Wc++0x-compat  -Wchar-subscripts -Wimplicit-int -Wimplicit-...
  • Linux中命令选项及参数简介

    千次阅读 2018-01-15 19:45:33
    登录Linux后,我们就可以在#或$符后面去输入命令,有的时候命令后面还会跟着“选项”(英文options)或“参数”(英文arguments)。即Linux中命令格式为: command [options] [arguments] //中括号代表是可选的,...
  • gcc优化选项

    千次阅读 2016-05-13 15:33:20
    linux gcc优化选项
  • vb.net 教程 1-1.5 变量

    千次阅读 2018-02-04 21:55:09
    变量是用来存放某个值的标识,它可以是一个数字、一个字符串、一个结构、一个类等。在代码中,变量的值是可以改变的。 在vb.net中声明/定义一个变量使用以下方法: dim 变量名称 as 变量类型 例如: dim strName as...
  • matlab 中变量的命名规则

    千次阅读 2020-03-20 17:36:09
    在matlab中,变量名是以字母开头,后接字母,数字或下划线的字符数列,最多63个字符 变量名区分字母大小写
  • 大多数软件包遵守如下约定俗成的规范:#1,首先从源代码生成目标文件(预处理,编译,汇编),"-c"选项表示不执行链接步骤。$(CC) $(CPPFLAGS) $(CFLAGS) example.c -c -o example.o#2,然后将目标文件连接为最终的结果...
  • 环境变量和shell变量

    千次阅读 2009-06-02 16:52:00
    14.1 本地变量本地变量在用户现在的shell 生命期的脚本中使用.这个值只在当前用户生命期有意义,如果在...要设置一本地变量,格式为:$variable-name=value ${variable-name=value}14.2 显示变量使用echo 可以显示变量
  • shell变量的类型

    万次阅读 2011-05-16 08:58:00
    13.10.2 命名惯例 变量名必须以字母或下划线字符开头。其余的字符可以是字母、数字(0~9)或下划线字符。任何其他的字符都标志着变量名的终止。名字是大小写敏感的。给变量赋值时,等号周围不能有任何空白...
  • GCC编译选项与GDB调试学习总结

    千次阅读 2017-09-24 14:16:21
    GCC编译选项与GDB调试学习总结GCC编译选项 GCC选项GCC编译相关的选项如下:–help:显示gcc帮助说明 -target-help:显示目标机器特定的命令行选项 –version:显示gcc版本号和版权信息 -E:只进行预处理,不编译 -S...
  • GCC 编译及编译选项

    千次阅读 2018-06-10 17:18:16
    俗话说:'工欲善其事,必先利其器',一直在工作中使用GNU C编译器(以下简称GCC),这里对GCC的一些警告选项细致的分析,并列举几个简单的例子[注1]供分析参考。 1、-Wall集合警告选项我们平时可能大多数情况只使用-...
  • gcc编译选项

    万次阅读 多人点赞 2014-02-24 10:37:53
    常用选项 -E:只进行预处理,不编译 -S:只编译,不汇编 -c:只编译、汇编,不链接 -g:包含调试信息 -I:指定include包含文件的搜索目录 -o:输出成指定文件名 高级选项 -v:详细输出编译过程中所...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 163,340
精华内容 65,336
关键字:

以下选项可以作为变量名的是