java不允许未经定义的常量直接出现在代码中

原创 2018年04月16日 16:07:07

不是报错,只是soanrqube检测觉得这样子不规范,这个也是阿里巴巴java编程手册中的一个规定,里面说法是不允许使用魔法值
java中,在使用sonarqube的时候,string类型的代码不允许直接使用未经定义的常量,什么是未经定义的产量呢?下面举个例子:

    //这个会报未经定义的常量
    String value = "常量";

一开始想到的解决方案是改成下面这个:

    //这样子就是定义了这个变量了,sonarqube也没有报错了
    String value = new String("常量");

但是里面有一个问题,那就是浪费内存。
浪费内存是,里面有两个对象,String value只是一个字符串变量,没有产生对象,new String(“常量”)不是原子操作,把它拆分为”常量”和new String(),首先会在字符串的常量池中查找有没有这个字符串”常量”,没有找到就会创建一个字符串对象”常量”在栈中,然后new String 会把这个字符串对象拷贝一份到堆中,返回这个对象的引用。

除此之外,我知道String是不可变的,但是那是创建了之后不可变,也就是线程安全,那么我的疑问是在创建的时候是线程安全的么?以下是关于这个方面的个人理解:
之所以说线程不安全,这里引入两个概念:原子操作指令重排

1.原子操作

  • 原子操作,可以理解为不可分割的操作,就是它已经小到不可以再切分为多个操作进行,那么在计算机中要么它完全执行了,要么它完全没有执行,它不会存在执行到中间状态,可以理解为没有中间状态。比如:赋值语句就是一个原子操作:
 n = 1; //这是一个原子操作 

假设n的值以前是0,那么这个操作的背后就是要么执行成功n等于1,要么没有执行成功n等于0,不会存在中间状态,就算是并发的过程中也是一样的。
下面看一句不是原子操作的代码:

int n =1;//不是原子操作

原因:这个语句中可以拆分为两个操作,1.声明变量n,2.给变量赋值为1,从中我们可以看出有一种状态是n被声明后但是没有来得及赋值的状态,这样的情况,在并发中,如果多个线程同时使用n,那么就会可能导致不稳定的结果。

2.指令重排

所谓指令重排,就是计算机会对我们代码进行优化,优化的过程中会在不影响最后结果的前提下,调整原子操作的顺序。比如下面的代码:

int a ;   // 语句1 
a = 1 ;   // 语句2
int b = 2 ;     // 语句3
int c = a + b ; // 语句4

正常的情况,执行顺序应该是1234,但是实际有可能是3124,或者1324,这是因为语句3和4都没有原子性问题,那么就有可能被拆分成原子操作,然后重排.

那么回到我们上面那个代码

    String value = new String("常量");
    //这不是原子操作,就是可以拆分,事实上先定义了一个String变量,然后创建了对象"常量",然后拷贝对象到堆中,将对象引用指向value。

上面代码如果在多线程中,有可能触发指令重排,如果有线程创建了对象,还没有将引用指过去,其他线程也就有可能创建多个这样的常量,有可能会导致其他问题出现。【如有错误,还请指教】

正确的改动方法:

1.使用常量,将项目的常量都抽取到一个class文件中:
2.使用format方法:

public class ConstantFile{
    public static final String name = "常量";//方法1
    public void myMethod(){
        String.format("常量,%s,%s",args1,args2);//方法2
    }
}

3.使用枚举类型:

public enum  ConstantFile {
  USA("美国",1),CHINA("中国",2);
  private String name;
  private int index;
  private ConstantFile(String name,int index){
    this.name=name;
    this.index=index;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getIndex() {
    return index;
  }

  public void setIndex(int index) {
    this.index = index;
  }
}

如有错误,还请指教,感激!!!

版权声明:如需转载,敬请标明出处。 https://blog.csdn.net/Aphysia/article/details/79961964

java项目中常量到底该怎么定义

背景:由于最近要接手一个老的系统,在看代码逻辑的过程中,看到程序中有很多魔法数字,所以着手把系统中的常量单独提取出来,然后定义在常量类中。本来这样就可以完工了,可是我有俩疑问: 1,为什么要将常亮提...
  • zl544434558
  • zl544434558
  • 2016-10-13 17:46:33
  • 2406

(二)常量定义

1:不允许有任何未经定义的常量出现在代码中 2:long 或 Long 初始赋值时,使用大写的L,不能使小写的l,小写容易根数字1混淆,造成误解。 3:不要使用一个常量类维护所有常量,按常量功能进行分...
  • yunfengfengfeng
  • yunfengfengfeng
  • 2017-10-08 11:59:16
  • 99

错误:‘xxxx’不能出现在常量表达式中

编译的时候,出现编译错误:  ‘xxx’不能出现在常量表达式中 代码如下: _term_pos_list.push_back(std::make_pairword, word_pos->pos>); ...
  • wangbin19911213
  • wangbin19911213
  • 2015-07-28 10:32:24
  • 758

“System.StackOverflowException”类型的未经处理的异常出现在 mscorlib.dll 中。

 疑难解答提示:确保您没有无限循环或无限递归。
  • gaofang2009
  • gaofang2009
  • 2010-08-30 16:27:00
  • 4802

java中的常量,是不是必须定义为static final的呢

今天看代码的时候,关于常量的引用,脑子中突然闪现出一个概念。java中的常量,是不是必须定义为static final的呢?final定义的字段,已经是不可改变的了,为什么还必须要加上一个static...
  • xueyepiaoling
  • xueyepiaoling
  • 2011-04-14 11:23:00
  • 9220

System.AccessViolationException”类型的未经处理的异常在 System.Data.dll 中发生

vs运行系统的时候出现如下异常,死活登陆不进去,但是别的同事却可以,说明不是代码的问题。 System.AccessViolationException”类型的未经处理的异常在 System.Dat...
  • hbu_pig
  • hbu_pig
  • 2014-02-26 10:53:36
  • 2705

提高你的Java代码质量吧:推荐使用枚举定义常量

一、分析  常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量。不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量。代码如下:  ...
  • p106786860
  • p106786860
  • 2013-09-10 09:18:59
  • 20450

一、(二) 常量定义

| 来源:阿里技术 微信公众号(id:ali_tech)。仅供于交流、学习、研究,勿用于商业用途! 1. 【强制】不允许任何魔法值(即未经定义的常量)直接出现在代码中。 反例:String key =...
  • qq_34803572
  • qq_34803572
  • 2017-09-30 17:11:44
  • 92

Java中定义常量几种方式

在开发中定义常量是很常见的事,但常量定义有哪几种方式可选?各种定义方式有什么优缺点?咱们就用这篇小文来梳理下^_^ 1.通过接口Interface来定义(不推荐) 定义方式...
  • hezikui1987
  • hezikui1987
  • 2017-08-20 22:51:18
  • 5479

java中定义常量方法

一、常量定义的基本注意事项。    在Java语言中,主要是利用final关键字(在Java类中灵活使用Static关键字)来定义常量。当常量被设定后,一般情况下就不允许再进行更改。如可以利用如下的...
  • bugDemo
  • bugDemo
  • 2012-06-10 20:33:57
  • 9268
收藏助手
不良信息举报
您举报文章:java不允许未经定义的常量直接出现在代码中
举报原因:
原因补充:

(最多只允许输入30个字)