本文适合对 Java 或 C 有一些了解的用户阅读,推荐阅读时间15分钟。

导言

写这个系列的原因?

我曾经听过一种说法,如果不了解Liunx的网络通讯,就很难理解理解Java的IO;如果不知道Java的IO也很难理解之后的NIO,Netty。(理解是建立在对底层的理解之上的

一门语言的设计是一项工程,是需要向很多其他编程语言、操作系统学习,站在巨人的肩膀上进行设计的;好的设计,好的语法也不是一蹴而就的,需要对之前版本的优点和缺点进行评估,再进行新语法的设想。
所以,本系列想采用Java从设计之初一直发展到Java8相关的新特性来讲述语言为何如此设计,以及语言发展各个重大版本的变化这个角度进行解析如何编写好“风格”的代码。

注:Java已经发展了很多年,目前为止最新的LTS版本为Java11。由于Java8商用已经较为普及,所以采用此版本。

这一节,先从布尔,常量一些特性开始讲起。

一、布尔类型

布尔类型在语法上类似于语言内置的常量,所以也做一些简单的介绍。

在过去编写C语言的代码时,由于缺少布尔类型(C99加入了布尔类型!),默认任何 非零 的值(不为null)假定为 true,把 零 和 null 假定为 false

#include<stdio.h>
int main() {
/* 输出 if(null) is false */
if (null)
print("if(null) is true");
else
print("if(null) is false"); /* 输出 if(0) is false */
if (0)
print("if(0) is true");
else
print("if(0) is false"); /* 输出 if(1) is true */
if (1)
print("if(1) is true");
else
print("if(1) is false");
}

这在当时没有问题,但这种写法可读性差,对程序员不太友好。

在这点上,C++往前走了一步,添加了布尔类型bool,但由于要兼容C语言,也可以同时使用C的语法(条件表达式接收int值),打印bool值真假实际为1和0。

#include <iostream>
using namespace std; int main(){
bool flag = true;
if(flag)
cout<<"true"<<endl;
else
cout<<"false"<<endl; cout<<flag<<endl; flag = false;
if(flag)
cout<<"true"<<endl;
else
cout<<"false"<<endl; cout<<flag<<endl; return 0;
} /* 输出
true
1
false
0
*/

Java也沿袭下来,增加了boolean类型,但条件表达式不接受int值,在语法上int值和boolean彻底无关。

package com.xx;

public class Demo {

    public static void main(String[] args) {
boolean b1 = true;
System.out.println(b1);
boolean b2 = false;
System.out.println(b2); }
} /*输出
true
false
*/

从C、C++一直到Java,可以看到语言设计者在一步步让程序编写者编出更直观的、人类可读的代码。

二、魔术数字(magic number)

编程初学者碰到一些特殊变量最开始可能会直接采用硬编码的方式编写。这种编码被人们称之为魔术数字(原因在于作者在若干月后,甚至自己也不知道这个数字是什么意义)

//100表示成功,其他值表示失败
if (status == 100) {
//成功处理
}
else {
//失败处理
}
其中100就是一个典型的魔术数字

这种编码习惯有以下两个明显的缺点

1.数值的意义难以了解

2.数值涉及变动时,可能要改不只一处

后来的编程人员使用了常量来代替魔术数字。常量名力求见名知意(某人说,好的代码是自解释(self-explanatory)的)。

常量的加入给程序带来了这两个好处。

1.增加可读性。

2.方便修改。

//1.这样的常量通常用相同的前缀表示同一类型 USER_SEX,且定义位置在最开头
//2.从C沿袭至今的全大写,下划线分隔
public static final int USER_SEX_MALE = 1;
public static final int USER_SEX_FEMALE = 0;

但是,在越来越多的常量使用中,人们又发现了自定义的常量也有一些难以解决的问题

1.需编译后才能生效
2.存在类型转换的风险

p.s. 第二点正是和C++的布尔值bool有着同样的问题。

再后来,常量的编写方式越来越多,比如注解;

通过注解使用的常量值


//application.properties
# 默认使用dev的配置文件
spring.profiles.active=dev

//application-dev.properties
# foo在开发环境的默认次数
default.foo.numbers = 10
//application-test.properties
#foo在测试环境的默认次数
default.foo.numbers = 1000


//application-prod.properties
# foo在生产环境的默认次数
default.foo.numbers = 100
import org.springframework.beans.factory.annotation.Value;

@Service
public class FooService {
@Value("${default.foo.numbers}")
private Integer fooNumbers;
}

使用注解的好处在于用户可以定义不同的application-xxx.properties等多个配置文件。每个文件可以定义同名不同值的常量, 在启动项目时通过启动参数 -Dspring.profiles.active=XXX 来选择使用的配置文件,实现改变配置时改变常量值

比如 dev配置文件的default.foo.numbers设置为10, test配置文件值设置为1000,根据 启动项目调用 -Dspring.profiles.active=test 调用到的值就是1000。

Java设计之初并没有考虑枚举类型,而是沿用从C一直以来的传统使用全局int/string值表示常量。为了让用户更好地使用常量,从1.5之后引入了枚举类型

/**
* 1.自动私有构造函数
* 2.强类型,不会因为类型转换带来问题
* 3.可以直接使用 == 比较,和String常量需要equals()对比,效率高
* 4.无需编译生效
*/
public enum UserSex {
male, //男
female, //女
;
//error
// UserSex();
public static UserSex get(String str) {
for (UserSex t : UserSex.values()) {
if (t.name().equals(str))
return t;
}
return null;
}
}

目前为止博主的最佳实践

对于只有真假的值,在Java中推荐使用布尔类型表示,比如是否为会员(isVip: true, false)。

对于超过两种以上或今后可能会增加新的类型的推荐用枚举表示。比如会员类型(VipType: week, month, year),考虑之后可能会新加入quarter等时间。

对于不同服之间同一个常量值由于各种需要测试等原因不一致,可以在各个服的配置文件定义。

Java随谈(一)魔术数字、常量和枚举的更多相关文章

  1. Qt 二进制文件读写(使用“魔术数字”)

    今天开始进入 Qt 的另一个部分:文件读写,也就是 IO.文件读写在很多应用程序中都是需要的.Qt 通过 QIODevice 提供了IO的抽象,这种设备(device)具有读写字节块的能力.常用的IO ...

  2. 【Java】定义魔法数字,以及枚举类的构造方法的使用

    JavaWeb项目中需要定义各种常量时,常用方法有: 写到Property配置文件中,用静态代码块优先加载配置文件.参考http://www.cnblogs.com/guxin/p/java-prop ...

  3. JAVA学习(三):Java基础语法(变量、常量、数据类型、运算符与数据类型转换)

    Java基础语法(变量.常量.数据类型.运算符与数据类型转换) 1.变量 Java中.用户能够通过指定数据类型和标识符来声明变量.其基本的语法为: DataType identifier; 或 Dat ...

  4. Java随谈(二)对空指针异常的碎碎念

    本文适合对 Java 空指针痛彻心扉的人阅读,推荐阅读时间25分钟. 若有一些Java8 函数式编程的基础可以当成对基础知识的巩固. 一.万恶的null 今天,我们简单谈谈null的问题.因为null ...

  5. ☕【Java技术指南】「编译器专题」重塑认识Java编译器的执行过程(常量优化机制)!

    问题概括 静态常量可以再编译器确定字面量,但常量并不一定在编译期就确定了, 也可以在运行时确定,所以Java针对某些情况制定了常量优化机制. 常量优化机制 给一个变量赋值,如果等于号的右边是常量的表达 ...

  6. 比较java与c语言中数字转换成字符的不同

    java java中将数字转换成字符非常方便,只要用一个"+"然后在跟一个空格行了.比如,你输入一个122 ,就会变成"122 ". import java.u ...

  7. java截取字符串中的数字

    java从字符串中提取数字 随便给你一个含有数字的字符串,比如: String s="eert343dfg56756dtry66fggg89dfgf"; 那我们如何把其中的数字提取 ...

  8. [转]浅谈https\ssl\数字证书

    浅谈https\ssl\数字证书 http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html 全球可信的 ...

  9. Linux Shell编程(13)——数字常量

    除非一个数字有特别的前缀或符号,否则shell脚本把它当成十进制的数.一个前缀为0的数字是八进制数.一个前缀为0x的数字是十六进制数.一个数用内嵌的#来求值则看成BASE#NUMBER(有范围和符号限 ...

随机推荐

  1. 多主机搭建etcd集群

    下载https://github.com/etcd-io/etcd/releases/download/v3.4.10/etcd-v3.4.10-linux-amd64.tar.gz分别放到两台主机上 ...

  2. 怎么下载chrome的扩展程序

    很多时候我们是没办法访问谷歌扩展应用程序 chrome应用商店的,这时候我们最好能把对应扩展应用程序下载保存,以便提供给其他人员使用. 搜索得到知乎有很全的方法: 如何导出并打包第三方chrome扩展 ...

  3. Fiddler扩展——导出Jmeter脚本

    前言 Fiddler,对于大家而言,应该早已耳熟能详,是个抓包神器,具体的使用,我就不多说了.如果对Fiddler的使用还不太熟练,可以翻看我以前一系列的博文.我罗列出来,方便大家阅读,如下所示: 1 ...

  4. 服务应用突然宕机了?别怕,Dubbo 帮你自动搞定服务隔离!

    某日中午,午睡正香的时候,接到系统的报警电话,提示生产某物理机异常宕机了,目前该物理机已恢复,需要重启上面部署的应用. 这时瞬间没有了睡意,登上堡垒机,快速重启了应用,系统恢复正常.本想着继续午睡,但 ...

  5. C++ strcmp与strncmp的比较

    C++ strcmp与strncmp的比较(转载)  原文链接:https://www.cnblogs.com/ybqjymy/p/12565444.html strcmp与strncmp都是用来比较 ...

  6. 腾讯大牛教你简单的自动化测试模型(Python+Selenium)

    今天讲解简单的自动化测试模型,对于刚接触自动化测试的同学,由于没有编程语言的基础,是搞不懂代码里面的函数.封装.包以及其他概念,只是了解字符串.数组.元组及字典这种最基本的名词,更不懂自动化测试框架了 ...

  7. Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案

    本文为霍格沃兹测试学院学员学习笔记. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”. ...

  8. wpf附加属性详解

    为什么使用附加属性 附加属性的一个用途是允许不同的子元素为父元素中定义的属性指定唯一的值. 此方案的一个具体应用是,让子元素通知父元素它们在用户界面 (UI) 中的呈现方式. 一个示例是 DockPa ...

  9. Android开发之下载服务器上的一张图片到本地java代码实现HttpURLConnection

    package com.david.HttpURLConnectionDemo; import java.io.FileOutputStream; import java.io.IOException ...

  10. MonoBehaviour生命周期与对象数据池应用

    预热游戏对象: tempObject = Instantiate(cubePrefab) as GameObject ; tempObject .SetActive( false ); 游戏对象tem ...