Java开发小技巧
文章目录
Java开发小技巧
平时开发中有一些小技巧,都不算很有技术含量,但在工作中运用这些技巧确实可以提高工作效率,这里把这些小技分享出来。
参数验证
提供的API接口类方法如有参数,都要做参数校验,参数校验不通过明确抛出异常或对应的响应码。到处写if表达式判断代码,正常的业务逻辑会被这些校验代码干扰,这里介绍两个用得比较多的方案。
Commons-lang的Validate
String val1 = " ";
Validate.notBlank(val1, "输入的参数val1=%s为空", val1);
String val2 = null;
Validate.notNull(val2, "输入的参数val2为null");
String[] arr1 = new String[0];
Validate.notEmpty(arr1, "数组为空");
List<String> lst1 = new ArrayList<String>();
Validate.notEmpty(lst1, "数组为空");
String[] arr2 = new String[0];
int idx = 3;
Validate.validIndex(arr2, idx, "索引超过数组范围");
short state1 = (short)1;
short validState = 3;
Validate.validState(state1==validState, "当前的状态不正确, state=%d", state1);
boolean valid = (3 == 4);
Validate.isTrue(valid, "表达式不合法");
BeanValidation
如果输入参数是pojo对象,采用BeanValidation方案更优雅一些。
public static void main(String[] args) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Pojo pojo = new Pojo();
pojo.setKey1("abcdef");
pojo.setKey2(3.3);
pojo.setTime1(new GregorianCalendar(2010, 3, 4).getTime());
Set<ConstraintViolation<Pojo>> violationSet = validator.validate(pojo);
if(violationSet.size() > 0) {
for (ConstraintViolation<Pojo> violation : violationSet) {
System.out.println(violation);
}
} else {
System.out.println("校验成功");
}
}
private static class Pojo{
@NotNull(message = "key1为空")
@Size(min = 6, max = 20, message = "key1的长度不正确")
private String key1;
@NotNull(message = "key2为空")
@DecimalMin(value = "0", message = "值不能小于0")
@DecimalMax(value = "100", message = "值不能大于100")
private Double key2;
@NotNull(message = "time1为空")
@Past(message = "时间不能大于现在")
private Date time1;
public String getKey1() {
return key1;
}
public void setKey1(String key1) {
this.key1 = key1;
}
public Double getKey2() {
return key2;
}
public void setKey2(Double key2) {
this.key2 = key2;
}
public Date getTime1() {
return time1;
}
public void setTime1(Date time1) {
this.time1 = time1;
}
}
重视Deprecated
调用标准库或第三方API时,一些接口上打上了Deprecated标记,而且一些还解释了准备废弃这个接口的原因及应该改用的写法。
// bad
java.net.URLEncoder#encode(java.lang.String);
// good
java.net.URLEncoder#encode(java.lang.String, java.lang.String);
// bad
java.net.URLDecoder#decode(java.lang.String);
// good
java.net.URLDecoder#decode(java.lang.String, java.lang.String);
// bad
java.util.Date#Date(int, int, int);
// good
java.net.URLDecoder#decode(java.lang.String, java.lang.String);
// bad
org.springframework.orm.hibernate3.support.HibernateDaoSupport#getSession().createSQLQuery(sql).executeUpdate();
// good
org.springframework.orm.hibernate3.support.HibernateDaoSupport#getHibernateTemplate().execute(new HibernateCallback<Void>() {
@Override
public Void doInHibernate(Session session) throws HibernateException, SQLException {
session.createSQLQuery(sql).executeUpdate();
return null;
}
});
Java文件操作
Java 7中引入了新的文件操作API,具有不少优点,新代码建议采用这套API操作文件。
可参考Java NIO File操作。
打印日志
平时打日志时有几个错误范例,打日志时要注意一下。
拼接字符串
// bad
Lg.info("abc " + 3 + " def " + 4 + " xxx " + 5);
// good
Lg.info(String.format("abc %d def %d xxx %d", 3, 4, 5))
打印异常堆栈至标准错误输出
// bad
e.printStackTrace();
Lg.error("执行出错");
// good
Lg.error("执行出错", e);
打印过长字符串
// bad
Lg.info(tooLongStr);
// good
if(Lg.isInfoEnabled()){
Lg.info(tooLongStr);
}
资源清理
网络连接、数据库连接、会话、HttpClient的连接等使用完后一定要进行资源清理。
以下是一些错误的示例:
private static Logger Lg = LoggerFactory.getLogger(ResourceCleanDemo.class); public static void main(String[] args) { Socket socket = null; BufferedReader reader = null; PrintWriter writer = null; try { socket = new Socket("127.0.0.1", 8080); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8.name())); writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8.name())); // do something ... socket.close(); writer.close(); reader.close(); } catch (IOException e){ Lg.error("出错", e); } }
private static Logger Lg = LoggerFactory.getLogger(ResourceCleanDemo.class); public static void main(String[] args) { Socket socket = null; BufferedReader reader = null; PrintWriter writer = null; try { socket = new Socket("127.0.0.1", 8080); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8.name())); writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8.name())); // do something ... } catch (IOException e){ Lg.error("出错", e); } finally { try { socket.close(); writer.close(); reader.close(); } catch (IOException e) { Lg.error("出错", e); } } }
正确的范例:
private static Logger Lg = LoggerFactory.getLogger(ResourceCleanDemo.class);
public static void main(String[] args) {
Socket socket = null;
BufferedReader reader = null;
PrintWriter writer = null;
try {
socket = new Socket("127.0.0.1", 8080);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8.name()));
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8.name()));
} catch (IOException e){
Lg.error("出错", e);
} finally {
IOUtils.closeQuietly(socket);
IOUtils.closeQuietly(writer);
IOUtils.closeQuietly(reader);
}
}
HttpClient连接池
HttpClient库为了提高性能,是使用了连接池的,应尽量使用连接池特性。
错误示例如下:
public static void main(String[] args) throws IOException {
for (int i = 0; i < 10; i++) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse resp = httpClient.execute(new HttpGet("www.baidu.com"));
// do something
....
httpClient.close();
}
}
正确示例如下:
private static final CloseableHttpClient httpClient = HttpClients.createDefault();
public static void main(String[] args) throws IOException {
for (int i = 0; i < 10; i++) {
HttpGet httpGet = null;
try {
httpGet = new HttpGet("www.baidu.com");
CloseableHttpResponse resp = httpClient.execute(httpGet);
// do something
....
} catch (Exception e) {
Lg.error("出错", e);
} finally {
httpGet.releaseConnection();
}
}
IOUtils.closeQuietly(httpClient);
}
善用Spring的工具类
Spring中有一些已经写好的工具类,代码都比较简单,即可以学习下,本时工作中用一用也可以提高开发效率。
org.springframework.dao.support.DataAccessUtils
org.springframework.util.StringUtils
org.springframework.util.CollectionUtils
org.springframework.util.Base64Utils
org.springframework.util.DigestUtils
org.springframework.util.FileCopyUtils
org.springframework.util.FileSystemUtils
org.springframework.util.ReflectionUtils
org.springframework.util.SocketUtils
org.springframework.beans.BeanUtils
Guava中一些有用的API
// 把Throwable包装成RuntimeException抛出
com.google.common.base.Throwables#propagate(Throwable throwable);
// 新集合类型
com.google.common.collect.Multiset
com.google.common.collect.Multimap
// Google Guava,详细用法参见http://jeremy-xu.oschina.io/2016/09/01/java%E4%B8%AD%E7%94%A8%E5%A5%BDcache/
com.google.common.cache.LoadingCache
// 异步任务执行完毕后自动执行指定的回调方法
com.google.common.util.concurrent.ListenableFuture
// 同步事件总线
com.google.common.eventbus.EventBus
// 异步事件总线
com.google.common.eventbus.AsyncEventBus
这里举几个例子:
Throwables抛出异常
public void someBusinessMethod(String param1){
try {
System.out.println(Integer.parseInt(param1));
} catch (NumberFormatException e) {
Throwables.propagate(e);
}
}
ListenableFuture示例
private static final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
public static void main(String[] args) {
ListenableFuture<Integer> future = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(10000L);
return new Integer(0);
}
});
Futures.addCallback(future, new FutureCallback<Integer>() {
@Override
public void onSuccess(Integer result) {
System.out.println(String.format("success, result: %d", result));
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
}
事件总线
private static EventBus eventBus = new EventBus("globalEventBus");
public static void main(String[] args) {
eventBus.register(new CustomEventHandler());
eventBus.register(new DeadEventHandler());
eventBus.post(new CustomEvent());
}
private static class CustomEventHandler{
@Subscribe
public void handleCustomEvent(CustomEvent event){
System.out.println(event);
}
}
private static class DeadEventHandler{
@Subscribe
public void handleDeadEvent(DeadEvent deadEvent){
System.out.println(deadEvent);
}
}
private static class CustomEvent{
}
重试逻辑
经常写代码实现业务的重试逻辑,可考虑spring-retry,用法可参考Retrying_Library_For_Java
工具技巧
java -XX:+PrintFlagsFinal
:打印出几乎所有的JVM支持的参数以及他们的默认值-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address={port}
:jvm开启jdwp,可运程调试-Dcom.sun.management.jmxremote=true -Djava.rmi.server.hostname=ip−Dcom.sun.management.jmxremote.port={port} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
:jvm开启jmx,可使用jconsole连接mybatis-generator的配置文件中加入
<property name="addRemarkComments" value="true" />
,可数据库表的备注可自动作为实体属性的注释IntelliJ IDEA
的几个重要的重构功能:Rename、Change Signature…、Move…、Copy…、Extract Constant…、Extract Method…、Extract Interface…、Pull Member Up…。
文章作者 Jeremy Xu
上次更新 2017-09-03
许可协议 © Copyright 2020 Jeremy Xu