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

不是报错,只是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;
  }
}

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

你可能感兴趣的:(java不允许未经定义的常量直接出现在代码中)