当前位置: 首页 > 科技观察

代码这样写,同事喊“666”

时间:2023-03-13 20:08:42 科技观察

1、MyBatis中多个查询条件不要写1=1。遇到多个查询条件时,使用where1=1可以轻松解决我们的问题。但是这很可能会造成非常大的性能损失,因为加入“where1=1”过滤条件后,数据库系统就不能使用索引等查询优化策略,数据库系统会被迫去扫描每一行数据(即全表扫描)比较行是否满足过滤条件。当表的数据量很大时,查询速度会很慢;另外,还会有SQL注入的风险。反例:selectcount(*)fromt_rule_BookInfowhere11=1ANDtitle=#{title}ANDauthor=#{author}正例:selectcount(*)fromt_rule_BookInfotitle=#{title}ANDauthor=#{author}UPDATE操作同理,可以用tag代替1=1。2、迭代entrySet()获取Map的key和value当循环中只需要获取Map的主键key时,迭代keySet()是正确的;但是,当需要主键key和value时,迭代entrySet()是比先迭代keySet()再通过get获取value更高效的方法。反例://Mapgetsvalue反例:HashMapma??p=newHashMap<>();for(Stringkey:map.keySet()){Stringvalue=map.get(key);}正例://Map获取键值示例:HashMapma??p=newHashMap<>();for(Map.Entryentry:map.entrySet()){Stringkey=entry.getKey();Stringvalue=entry.三、使用Collection.isEmpty()检测是否为空使用Collection.size()检测是否为空逻辑上是正确的,但是使用Collection.isEmpty()使得代码的可读性更强,可以获得更好的性能;除此之外,任何Collection.isEmpty()的实现都有O(1)的时间复杂度,不需要多次循环遍历,但有些通过Collection.size()方法实现的可能是O(1)(n)反例:LinkedListcollection=newLinkedList<>();if(collection.size()==0){System.out.println("collectionisempty.");}正例:LinkedListcollection=newLinkedList<>();if(collection.isEmpty()){System.out.println("collectionisempty.");}//检查是否为null,可以使用CollectionUtils.isEmpty()if(CollectionUtils.isEmpty(collection)){System.out.println("collectionisnull.");}四、尽量在初始化时指定collection的大小有效减少集合的扩容次数,因为每次扩容集合的时间复杂度很可能是O(n),耗时耗性能反例://初始化列表,向列表中添加元素反例:int[]arr=newint[]{1,2,3,4};Listlist=newArrayList<>();for(inti:arr){list.add(i);}正例://初始化list,向list中添加元素正例:int[]arr=newint[]{1,2,3,4};//指定集合list的容量Listlist=newArrayList<>(arr.length);for(inti:arr){list.add(i);}5.使用StringBuilder连接字符串。一般Java会在编译时优化字符串拼接,但是循环中的字符串拼接无法在编译时优化,所以需要使用StringBuilder来代替。反例://Concatenatingstringsinaloop反例Stringstr="";for(inti=0;i<10;i++){//ConcatenatingstringsinaloopJava不会优化它str+=i;}正例://循环拼接字符串的正例Stringstr1="Love";Stringstr2="Courage";StringstrConcat=str1+str2;//Java编译器会在这种正常模式下优化字符串拼接StringBuildersb=newStringBuilder();for(inti=0;i<10;i++){//在循环中,Java编译器无法优化,所以需要使用StringBuildersb.append(i);}6.如果需要频繁调用Collection。contains方法使用Set。在Java集合类库中,List的contains方法一般时间复杂度为O(n)。如果代码需要频繁调用contains方法查找数据,先将集合列表转化为HashSet实现,O(n)的时间复杂度为O(1)。反例://频繁调用Collection.contains()反例Listlist=newArrayList<>();for(inti=0;i<=Integer.MAX_VALUE;i++){//时间复杂度为O(n)if(list.contains(i))System.out.println("listcontains"+i);}例子://频繁调用Collection.contains()示例Listlist=newArrayList<>();Setset=newHashSet<>();for(inti=0;i<=Integer.MAX_VALUE;i++){//时间复杂度为O(1)if(set.contains(i)){System.out.println("listcontains"+i);}}7.使用静态代码块赋值静态成员变量For集合类型的静态成员变量,应该使用静态代码块来赋值,而不是集合实现。反例://给静态成员变量赋值反例privatestaticMapmap=newHashMap(){{map.put("Leo",1);map.put("Family-loving",2);map.put("Coldontheoutsidepassionateontheinside",3);}};privatestaticListlist=newArrayList<>(){{list.add("射手座");list.add("迷人");list.add("完美主义者");}};正例://静态成员变量的赋值正例privatestaticMapmap=newHashMap();static{map.put("Leo",1);map.put("Family-loving",2);map.put("Coldontheoutsidepassionateontheinside",3);}privatestaticListlist=newArrayList<>();static{list.add("射手座");list.add("迷人");list.add("Perfectionist");}八、删除不用的局部变量、方法参数、私有方法、字段和多余的括号。9.工具类中屏蔽构造函数工具类是静态字段和函数的集合,不应该被实例化;但是,Java为每个没有显式定义构造函数的类都增加了一个隐式公共构造函数,为了避免不必要的实例化,应该显式定义一个私有构造函数来屏蔽这个隐式公共构造函数。反例:publicclassPasswordUtils{//工具类构造函数反例privatestaticfinalLoggerLOG=LoggerFactory.getLogger(PasswordUtils.class);publicstaticfinalStringDEFAULT_CRYPT_ALGO="PBEWithMD5AndDES";publicstaticStringencryptPassword(StringaPassword)throwsIOException{returnnewPasswordUtils(aPassword).encrypt();}正例:publicclassPasswordUtils{//tool类构造函数正例privatestaticfinalLoggerLOG=LoggerFactory.getLogger(PasswordUtils.class);//定义一个私有构造函数来屏蔽这个隐式公共构造函数privatePasswordUtils(){}publicstaticfinalStringDEFAULT_CRYPT_ALGO="PBEWithMD5AndDES";publicstaticStringencryptPassword(wordUtilsPassword)throwsIOExceptions{new(aPassword).encrypt();}10.删除多余的异常捕获和运行。用catch语句捕获到异常后,如果什么都不处理,只是再次抛出异常,和不捕获异常的效果是一样的。可以删除此代码块或添加其他处理。反例://异常反例privatestaticStringfileReader(StringfileName)throwsIOException{try(BufferedReaderreader=newBufferedReader(newFileReader(fileName))){Stringline;StringBuilderbuilder=newStringBuilder();while((line=reader.readLine())!=null){builder.append(line);}returnbuilder.toString();}catch(Exceptione){//只是重复抛出异常,没有任何处理throwe;}}正例://异常过多正例privatestaticStringfileReader(StringfileName)throwsIOException{try(BufferedReaderreader=newBufferedReader(newFileReader(fileName))){Stringline;StringBuilderbuilder=newStringBuilder();while((line=reader.readLine())!=null){builder.append(line);}returnbuilder.toString();//删除多余的抛出异常,或增加其他处理:/*catch(Exceptione){return"fileReaderexception";}*/}}11.字符串转换使用String.valueOf(value)代替""+value转换其他对象时或类型为字符串,使用String.valueOf(value)比""+value更有效。反例://将其他对象或类型转换为字符串反例:intnum=520;//""+valueStringstrLove=""+num;正例://将其他对象或类型转换成字符串正例:intnum=520;//String.valueOf()效率更高StringstrLove=String.valueOf(num);十二。避免使用BigDecimal(double)BigDecimal(double)存在精度丢失的风险,在精确计算或者数值比较场景下可能会丢失导致业务逻辑异常。反例://BigDecimal反例BigDecimalbigDecimal=newBigDecimal(0.11D);正例://BigDecimal正例BigDecimalbigDecimalbigDecimal1=bigDecimal.valueOf(0.11D);第十三、返回一个空数组和集合而不是null如果程序返回null,需要调用者强制检测null,否则会抛出空指针异常;返回空数组或空集合有效避免了调用者因为没有检测到null而抛出空指针异常,也可以删除调用者检测到null的语句,使代码更加简洁。反例://Returnnull反例publicstaticResult[]getResults(){returnull;}publicstaticListgetResultList(){returnull;}publicstaticMapgetResultMap(){returnnull;}正例://returnemptyarray和Emptyset正例}104.优先使用常量或某些值来调用equals方法。对象的equals方法很容易抛出空指针异常。您应该使用常量或具有特定值的对象来调用equals方法。反例://调用equals方法反例privatestaticbooleanfileReader(StringfileName)throwsIOException{//可能抛出空指针异常returnfileName.equals("Charming");}正例://调用equals方法正例privatestaticbooleanfileReader(StringfileName)throwsIOException{//使用常量或具有一定值的对象调用equals方法return"Charming".equals(fileName);//或使用:java.util.Objects.equals()方法returnObjects.equals("Charming",fileName);}十五、枚举的属性字段必须是私有的,不可变的枚举通常用作常量。如果枚举中有公共属性字段或者设置字段方法,那么这些枚举常量的属性可以很容易的被修改;理想情况下,枚举示例中的属性字段是私有的,在私有构造函数中赋值,没有对应的Setter方法,最好加上final修饰符。反例:publicenumSwitchStatus{//枚举属性字段反例DISABLED(0,"Disabled"),ENABLED(1,"Enabled");publicintvalue;privateStringdescription;privateSwitchStatus(intvalue,Stringdescription){this.value=value;this.description=description;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(Stringdescription){this.description=description;}}正例:publicenumSwitchStatus{//枚举属性字段正例DISABLED(0,"Disabled"),ENABLED(1,"enable");//最终修改privatefinalintvalue;privatefinalStringdescription;privateSwitchStatus(intvalue,Stringdescription){this.value=value;this.description=description;}//无Setter方法publicintgetValue(){returnvalue;}publicStringgetDescription(){returndescription;}}十六、tring.split(Stringregex)在使用String的plit方法时需要对一些关键字进行翻译,传入的分隔字符串为正则表达式,则对一些关键字(如.[]()|等)需要转义。反例://String.split(Stringregex)反例String[]split="a.ab.abc".split(".");System.out.println(Arrays.toString(split));//结果为[]String[]split1="a|ab|abc".split("|");System.out.println(Arrays.toString(split1));//结果为["a","|","a","b","|","a","b","c"]正例://String.split(Stringregex)正例//。需要翻译String[]split2="a.ab.abc".split("\\.");System.out.println(Arrays.toString(split2));//结果为["a","ab","abc"]//|需要翻译String[]split3="a|ab|abc".split("\\|");System.out.println(Arrays.toString(split3));//结果是["a","ab","abc"]