知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技

Java 高效代码50例

发表时间:2022-03-23来源:网络

导读#

  世界上只有两种物质:高效率和低效率;世界上只有两种人:高效率的人和低效率的人。----萧伯纳

常量&变量#

直接赋值常量,禁止声明新对象#

  直接赋值常量值,只是创建了一个对象引用,而这个对象引用指向常量值。

反例#

 

Long i=new Long(1L); String s=new String("abc");

正例#

Long i=1L; String s="abc";

当成员变量值无需改变时,尽量定义为静态常量#

  在类的每个对象实例中,每个成员变量都有一份副本,而成员静态常量只有一份实例。

反例#

public class HttpConnection{ private final long timeout=5L; ... }

正例#

public class HttpConnection{ private static final long timeout=5L; ... }

尽量使用基本数据类型,避免自动装箱和拆箱#

  Java中的基本数据类型double、float、long、int、short、char、boolean,分别对应包装类Double、Float、Long、Integer、Short、Character、Boolean。

  Jvm支持基本类型与对象包装类的自动转换,被称为自动装箱和拆箱。装箱和拆箱都是需要CPU和内存资源的,所以应尽量避免自动装箱和拆箱。

反例#

Integer sum = 0; int[] values = { 1, 2, 3, 4, 5 }; for (int value : values) { sum+=value; }

正例#

int sum = 0; int[] values = { 1, 2, 3, 4, 5 }; for (int value : values) { sum+=value; }

如果变量的初值会被覆盖,就没有必要给变量赋初值#

反例#

public static void main(String[] args) { boolean isAll = false; List userList = new ArrayList(); if (isAll) { userList = userDAO.(); } else { userList=userDAO.(); } } public class Users { } public static class userDAO { public static List () { return null; } public static List () { return null; } }

正例#

public static void main(String[] args) { boolean isAll = false; List userList; if (isAll) { userList = userDAO.(); } else { userList=userDAO.(); } } public class Users { } public static class userDAO { public static List () { return null; } public static List () { return null; } }

尽量使用函数内的基本类型临时变量#

  在函数内,基本类型的参数和临时变量都保存在栈(Stack)中,访问速度较快;对象类型的参数和临时变量的引用都保存在栈(Stack)中,内容都保存在堆(Heap)中,访问速度较慢。在类中,任何类型的成员变量都保存在堆(Heap)中,访问速度较慢。

反例#

public final class Accumulator { private double result = 0.0D; public void addAll(@NonNull double[] values) { for (double value : values) { result += value; } } }

正例#

public final class Accumulator { private double result = 0.0D; public void addAll(@NonNull double[] values) { double sum = 0.0D; for (double value : values) { sum += value; } result += sum; } }

尽量不要在循环体外定义变量#

  在老版本JDK中,建议“尽量不要循环体内定义变量”,但是在新版的JDK中已经做了优化。通过对编译后的字节码分析,变量定义在循环体外和循环体内没有本质的区别,运行效率基本上是一样的。反而,根据“局部变量作用域最小化”原则,变量定义在循环体内更科学更便于维护,避免了延长对象生命周期导致延缓回收问题。

反例#

UserVO userVo; List userDOList=new ArrayList(5); for(UserVO vo:userDOList) { userVo=new UserVO(); ... }

正例#

List userDOList=new ArrayList(5); for(UserVO vo:userDOList) { UserVO userVo=new UserVO(); ... }

不可变的静态常量,尽量使用非线程安全类#

  不可变的静态常量,虽然需要支持多线程访问,也可以使用非线程安全类。

反例#

public static final Map CLASS_MAP; static { Map classMap=new ConcurrentHashMap(16); classMap.put("VARCHAR", java.lang.String.class); ... CLASS_MAP=Collections.unmodifiableMap(classMap); }

正例#

public static final Map CLASS_MAP; static { Map classMap=new HashMap(16); classMap.put("VARCHAR", java.lang.String.class); ... CLASS_MAP=Collections.unmodifiableMap(classMap); }

不可变的成员变量,尽量使用非线程安全类#

  不可变的成员变量,虽然需要支持多线程访问,也可以使用非线程安全类。

反例#

private List strategyList; private Map strategyMap; public void afterPropertiesSet() { if (CollectionUtils.isNotEmpty(strategyList)) { int size=(int)Math.ceil(strategyList.size()*4.0/3); Map map=new ConcurrentHashMap(size); strategyMap=Collections.unmodifiableMap(map); } }

正例#

private List strategyList; private Map strategyMap; public void afterPropertiesSet() { if (CollectionUtils.isNotEmpty(strategyList)) { int size=(int)Math.ceil(strategyList.size()*4.0/3); Map map=new HashMap(size); strategyMap=Collections.unmodifiableMap(map); } }

对象&类#

禁止使用JSON转换对象#

  JSON提供把对象转换为JSON字符串、把JSON字符串转为对象的功能,于是被某些人用来转换为对象。这种对象转换方式,虽然在功能上没有问题,但是在性能上却存在问题。

反例#

List userDOList=new ArrayList(); List userVOList=JSON.parseArray(JSON.toJSONString(userDOList), UserVO.class);

正例#

List userDOList=new ArrayList(); List userVOList=new ArrayList(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); ... }

尽量不使用反射赋值对象#

  用反射赋值对象,主要优点是节省了代码量,主要缺点却是性能有所下降。

反例#

List userDOList=new ArrayList(); List userVOList=new ArrayList(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); BeanUtils.copyProperties(userDO,vo); userVOList.add(vo); }

正例#

List userDOList=new ArrayList(); List userVOList=new ArrayList(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); vo.setId(userDO.getId()); ... userVOList.add(vo); }

采用Lambda表达式替换内部匿名类#

  对于大多数刚接触JDK8的同学来说,都会认为Lambda表达式就是匿名内部类的语法糖。实际上,Lambda表达式在大多数虚拟机中采用invokeDynamic指令实现,相对于匿名内部类在效率上会更高一些。

反例#

List userList=new ArrayList(); Collections.sort(userList,new Comparator() { @Override public int compare(User o1, User o2) { Long userId1=o1.getId(); Long userId2=o2.getId(); return userId1.compareTo(userId2); } });

正例#

List userList=new ArrayList(); Collections.sort(userList,(User o1,user o2)->{ Long userId1=o1.getId(); Long userId2=o2.getId(); return userId1.compareTo(userId2); });

尽量避免定义不必要的子类#

  多一个类就需要多一份类加载,所以尽量避免定义不必要的子类。

反例#

public static final Map CLASS_MAP=Collections.unmodifiableMap(new HashMap(16){ private static final long serialVersionUID=1L; { put("VARCHAR", java.lang.String.class); } });

正例#

public static final Map CLASS_MAP; static { Map classMap=new HashMap(); classMap.put("VARCHAR", java.lang.String.class); CLASS_MAP=Collections.unmodifiableMap(classMap); }

尽量指定类的final修饰符#

  为类指定final修饰符,可以让该类不可以被继承。如果指定了一个类为final,则该类所有的方法都是final的,Java编译器会寻找机会内敛所有的final方法。内敛对于提升Java运行效率作用重大,具体可参见Java运行期优化,能够使性能平均提高50%。

反例#

public class DateHelper{ ... }

正例#

public final class DateHelper{ ... }

注:使用Spring的AOP特性时,需要对Bean进行动态代理,如果Bean类添加了final修饰,会导致异常。

方法#

把跟类成员变量无关的方法声明成静态方法#

  静态方法的好处就是不用生成类的实例就可以直接调用。静态方法不再属于某个对象,而是属于它所在的类。只需要通过其类名就可以访问,不需要再消耗资源去反复创建对象。即便在类内部的私有方法,如果没有使用到类成员变量,也应该声明为静态方法。

反例#

public int getMonth(Date date) { Calendar calendar=Calendar.getInstance(); calendar.setTime(date); return calendar.get(calendar.MONTH)+1; }

正例#

public static int getMonth(Date date) { Calendar calendar=Calendar.getInstance(); calendar.setTime(date); return calendar.get(calendar.MONTH)+1; }

尽量使用基本数据类型作为方法参数类型,避免不必要的装箱、拆箱和空指针判断#

反例#

public static double sum(double value1,double value2) { double double1=Objects.isNull(value1)?0.0D:value1; double double2=Objects.isNull(value2)?0.0D:value2; return double1+double2; }

正例#

public static double sum(double value1,double value2) { return value1+value2; }

尽量使用基本数据类型作为方法返回值类型,避免不必要的装箱、拆箱和空指针判断#

  在JDK类库的方法中,很多方法返回值都采用了基本数据类型,首先是为了避免不必要的装箱和拆箱,其次是为了避免返回值的空指针判断。比如:

Collection.isEmpty() Map.size()

反例#

public static void main(String[] args) { UserDO userDO=new UserDO(); boolean isValid=isValid(userDO); if (Objects.isNull(isValid)&&Objects.isNull(isValid)) { } } public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }

正例#

public static void main(String[] args) { UserDO userDO=new UserDO(); if (isValid(userDO)) { } } public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }

协议方法参数值非空,避免不必要的空指针判断#

  协议编程,可以@NonNull和@Nullable标注参数,是否遵循全凭调用者自觉。

反例#

public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }

正例#

public static Boolean isValid(@NonNull UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }

协议方法返回值非空,避免不必要的空指针判断#

  协议编程,可以@NonNull和@Nullable标注参数,是否遵循全凭实现者自觉。

反例#

public static void main(String[] args) { OrderService orderService=null; List orderList=orderService.((long) 5); } public interface OrderService{ public List (Long userId); }

正例#

public static void main(String[] args) { OrderService orderService=null; List orderList=orderService.((long) 5); } public interface OrderService{ @NonNull public List (Long userId); }

被调用方法已支持判空处理,调用方法无需再进行判空处理#

反例#

UserDO userDO = null; if (StringUtils.isNotBlnk(values)) { userDO = JSON.parseObject(values, UserDO.class); }

正例#

UserDO userDO = JSON.parseObject(values, UserDO.class);

尽量避免不必要的函数封装#

  方法调用会引起入栈和出栈,导致消耗更多的CPU和内存,应当尽量避免不必要的函数封装。当然,为了使代码更简洁、更清晰、更易维护,增加一定的方法调用所带来的性能损耗是值得的。

反例#

public static void main(String[] args) { boolean isVip=isVip(User.getVip()); } public static boolean isVip(boolean isVip) { return Boolean.TRUE.equals(isVip); }

正例#

public static void main(String[] args) { boolean isVip=Boolean.TRUE.equals(User.getVip()); }

尽量指定方法的final修饰符#

  方法指定final修饰符,可以让方法不可以被重写,Java编译器会寻找机会内敛所有final方法。内敛对于提升Java运行效率作用重大,具体可参见Java运行期优化,能够使性能平均提高50%。

注:所有的private方法会隐士地被指定final修饰符,所以无需再为其指定final修饰符。

反例#

public class User { public int getAge() { return 10; } }

正例#

public class User { public final int getAge() { return 10; } }

注:使用Spring的AOP特性时,需要对Bean进行动态代理,如果方法添加了final修饰,将不会被代理。

表达式#

尽量减少方法的重复调用#

反例#

List userList=new ArrayList(); for (int i = 0; i < userList.size(); i++) { ... }

正例#

List userList=new ArrayList(); int userLength=userList.size(); for (int i = 0; i < userLength; i++) { ... }

尽量避免不必要的方法调用#

反例#

List userList=userDAO.(); if (isAll) { userList=userDAO.(); }

正例#

List userList; if (isAll) { userList=userDAO.(); }else { userList=userDAO.(); }

尽量使用移位来代替正整数乘除#

  用移位操作可以极大地提高性能。对于乘除2^n(n为正整数)的正整数计算,可以用移位操作来代替。

反例#

int num1=a*4; int num2=a/4;

正例#

int num1=a2;

提取公共表达式,避免重复计算#

  提取公共表达式,只计算一次值,然后重复利用值。

反例#

double distance=Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));

正例#

double dx=x2-x1; double dy=y2-y1; double distance=Math.sqrt(dx*dx+dy*dy); 或 double distance=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));

尽量不在条件表达式中用!取反#

  使用!取反会多一次计算,如果没有必要则优化掉。

反例#

if(!(a>=10)){ .... }else{ .... }

正例#

if(a
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜