JAVA自用技巧记录(不定期更新)
代码设计的要求(不分顺序)
1.算法
2.格式风格(注释、排版)
3.容错机制
4.代码复用性(弹性)
5.技术复杂性(使用多线程代替、第三方工具)
Git暂存
代码写了一半,然后来了需求要先改,可以用git stash 提交为暂存
完成任务后git stash pop 获取回来
long的乘法计算
public static void main(String[] args) {
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; //应该要24L
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
预期是1000,但是实际是5,因为在运算中的int丢失了信息,所以要记得转成long。
三目运算符
boolean条件 ? 表达式1 : 表达式 2
右结合性、表达式1和2中如果都为基本数据类型, 整个表达式的运算结果由容量高的决定。
1 假如表达式1和表达式2具有相同的类型,那么整个条件运算符结果的类型就是这个类型。
2 假如一个表达式的类型是T,T是byte或short或char,另一个表达式的类型是int类型的常量表达式,而且这个常量表达式的值是可以用类型T表示的(也就是说,常量表达式的值是在类型T的取值范围之内),那么整个条件运算符结果的类型就是T。
3 除以上情况外,假如表达式1和表达式2的类型不同,那么将进行类型提升,整个条件运算符结果的类型就是提升后的类型
int n = 7; System.out.println(n>6?1:2.0);//1.0 规则3 System.out.println(n>6?1:2);//1 规则1 System.out.println(n>6?'a':2L);//97L 规则3 System.out.println(n>6?'a':2);//a 规则2 System.out.println(n>6?'a':Character.MAX_VALUE);//a 规则2 System.out.println(n = (n>6?'a':Character.MAX_VALUE+1));//97 规则3 Object object=(n>6?'a':2L); System.out.println(object instanceof Long); //true
JSON 的转换
谷歌封装好了一个类:com.google.gson.Gson; 使用它就好
Map<String, Object> dataMap = GsonUtils.getJson(jsonStr, Map.class);
不过有时候想要直接String类型或者谷歌的转换有问题,可以使用这种:
Map<String, String> beanMap = JSON.parseObject(ret,new TypeReference<Map<String, String>>() {});
日期操作
获取当前日期
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
System.out.println(df.format(new Date()));// new Date()为获取当前系统时间
将字符串转化为Date
String dateString="2017-09-17";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
String date=df.parse(dateString); //需要抛出异常
获取两个日期之间的日期
private List<Date> getBetweenDates(Date start, Date end) { List<Date> result = new ArrayList<Date>(); Calendar tempStart = Calendar.getInstance(); tempStart.setTime(start); tempStart.add(Calendar.DAY_OF_YEAR, 1); //如果起始日期包含当天的话1改为0 Calendar tempEnd = Calendar.getInstance(); tempEnd.setTime(end);
//如果结束如期包含当天的话,可以手动延后一天
//tempEnd.add(Calendar.DAY_OF_YEAR, 1);
while (tempStart.before(tempEnd)) { result.add(tempStart.getTime()); tempStart.add(Calendar.DAY_OF_YEAR, 1); } return result; }
Spring
实例化、依赖注入后做一些后续初始化工作
@Override
public void afterPropertiesSet() throws Exception {
//do something
}
Spring注入静态变量的变通方法
//注入一个对象
@Value("${somethingVar}")
protected String _inputString;
protected static String inputString;
//通过init来变相注入静态变量
private void init() {
inputString = _inputString;
}
Map
Map的遍历
// 第一种
Set set = map.keySet();
Iterator it = set.iterator();
while (it.hasNext()) {
String str = it.next().toString();
}
// 第二种
Set<Entry<String, String>> entryset = map.entrySet();
Iterator iter = entryset.iterator();
while (iter.hasNext()) {
Entry<String, String> entry = (Entry<String, String>) iter.next();
}
// 第三种
for (Entry<String, String> entry : map.entrySet()) {
String strkey = entry.getKey();
String strval = entry.getValue();
}
//第四种,单独要KEY或者Values
//遍历map中的键
for (Integer key : map.keySet()) {
System.out.println("Key = " + key);
}
//遍历map中的值
for (Integer value : map.values()) {
System.out.println("Value = " + value);
}
Map如果要顺序的话用
LinkedHashMap,如果要求同步,建议用: Map<String String> map = Collections.synchronizedMap(new LinkedHashMap(<String String));
需要大规模并发插入时,则建议使用ConcurrentHashMap<String, Map<String, String>> resultMap = new ConcurrentHashMap<>();
判断String是否为空以及值为空
以前用s == null || s.equals("")但是equals耗时相对久一点,建议使用s == null || s.length() <= 0,代码规范的话,推荐用isEmpty来代替判断。
类型参数。常见的如:
- T 代表一般的任何类。
- E 代表 Element 的意思,或者 Exception 异常的意思。
- K 代表 Key 的意思。
- V 代表 Value 的意思,通常与 K 一起配合使用。
- S 代表 Subtype 的意思。
通配符有 3 种形式。
<?>被称作无限定的通配符。<? extends T>被称作有上限的通配符。<? super T>被称作有下限的通配符。
集合转数组的方法:
改方法必须使用集合的 toArray(T[] array),传入的是类型完全 一样的数组,大小就是 list.size()。 反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它 类型数组将出现 ClassCastException 错误。 正例:
List list = new ArrayList(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array);
Object、T(泛型)、?区别
Object是所有类的类类型,它的适用范围最广,无论是自定义的还是原生都能符合Object
T是限定类型,当然你可以选择让T为Object,
例子:List<T> 实例化后List<String>和List<Object>都是合法的,但是前者限定类型只能为String的集合,而后者的类型是Object。
?是不知道类型,有时候Object范围太大了,我只想限定某个类型的,但是不知道太具体的信息,可以尝试用 ? extends Coll
获取方法名
调用者的名字:new Exception().getStackTrace()[1].getMethodName();
本方法:new Exception().getStackTrace()[0].getMethodName();
使用Eclipse的代码格式化快捷键Alt+Shift+F时遇到一行太长被迫换行的话
Windows->Preferences->Java->Code Style->Formatter->Edit->Line Wrapping->Maximum line width 设置为200即可
JAVA执行CMD命令(Windows7)
private static void cmdTest() { try { String date="2017-09-21"; Runtime run=Runtime.getRuntime(); //执行CMD命令,以修改时间为例子 String command="cmd.exe /c date"+" "+(date); System.out.println(command); run.exec(command); } catch (IOException e) { e.printStackTrace(); } }
CMD下的JAVA语句
在控制台里输入java -jar XXX.jar即可以运行这个jar。
系统重启运行某个JAR包(Windwos)
有时候有些JAR包无法双击运行,可以先添加一个批处理文件: java -jar d:/XXX.jar
另存为XXX.bat文件,并将快捷方式放置到“启动”目录中.
如果还想让他不显示黑色的框框:
set ws=WScript.CreateObject("WScript.Shell") ws.Run "bat的路径(例子:C:\XXX.bat) /start",0
保存为一个vbs文件。(XXX.vbs)
由于测试用的系统是windows2008server,所以不能单纯的添加到“启动”菜单,而是要通过设置计划任务来达到执行,尤其要选择“无论是否登录,都要执行”,缺省是需要登录的
定义变量写在循环外真的会有区别吗?
List<String> list=new ArrayList<>(); for (int i = 0; i < 10000; i++) { String string="is"+i; list.add(string); } List<String> list2=new ArrayList<>(); String string; for (int i = 0; i < 10000; i++) { string="is"+i; list2.add(string); }
以上两种写法,估计会有人说第一种的写法会影响效率,第二更加好一点,然而~真相却是:
通过反编译器查看

其实编译器已经帮你做好了,所以不用纠结这一点。。。
HashSet的实现

底层由HashMap实现,将传进来的值复制给key保证唯一。
pom.xml文件打红×时,按alt+F5,勾选Force Update of Snapshots/Releases 进行强制更新
调用SqlServer时,有些存日期是float格式,JAVA读取后识别成double,这时候转换容易出问题
例如:20170908读取到java后变成2.0170908E7是一串double数字,
解决方法就是在查询时就转换为字符串:
convert(varchar(20),convert(int,查询的字段))
获取SqlServer的数据库时间,由于分布式,所以时间以数据库为准
/** * @Title: getDbDate * @Description: 获取时间 * @return * @throws Exception 参数说明 * @return String 返回类型 */ public Date getDate() throws Exception { // 获取数据库的时间 String sql = "SELECT getdate() AS dt"; Map<String, Object> list = riskControlSqlServerHelper.query(sql); if (list==null||list.isEmpty()) { throw new Exception("获取数据库时间异常"); } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); Date date=sdf.parse(list.get("dt")+""); return date; }
split空格 split("\\s+")
查找某个端口是否被占用 netstat -aon|findstr "端口号"
枚举型的应用
private enum STATUS{
fail("发送失败"),
succes("发送成功");
private String string;
private String code;
private STATUS(String string)
{
this.string=string;
this.code=this.ordinal()+"";
}
}
System.out.println(STATUS.fail); //fail
System.out.println(STATUS.succes); //succes
System.out.println(STATUS.fail.string); //发送失败
System.out.println(STATUS.succes.string); //发送成功
System.out.println(STATUS.fail.ordinal()); //0 int
System.out.println(STATUS.succes.ordinal()); //1 int
System.out.println(STATUS.fail.code); //0 String
System.out.println(STATUS.succes.code); //1 String
List转数组
List<String> list = new ArrayList(); //假设已经有数据了
String[] datas = new String[list.size()];
for(int i=0;length=datas.length;i<length;i++){
datas[i]=list.get(i);
}
Eclipse常用快捷键
ctrl+shift+T打开类型查找,速度比较快
重写类的equals方法
//Test类,已经定义了属性id @Override public boolean equals(Object other) { if (this == other) { return true; } else if (!(other instanceof Test)) { return false; } else { return ((Test) other).getId() == getId(); } }
重写hashCode
//String的hashCode实现方式
private int hash;
@Override
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < val.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
RequestMapping
Controller层需要加@RestController以及@RequestMapping("/地址")
Service层需要加@Service
Dao层需要加@Repository
@RequestMapping("/save") public String saveIntoMongoDBBy() { //dosomething } @RequestMapping("/save/{userID}") public String saveIntoMongoDBBy(@PathVariable("userID") Integer id) { //you can use userID to do something }
一键切换JDK版本,windows的bat操作
首先安装好JDK7和JDK8,
做两个BAT文件
JDK7:
::删除环境变量JAVA_HOME @echo off echo Delete java_home set regpath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment set evname=JAVA_HOME reg delete "%regpath%" /v "%evname%" /f ::添加环境变量JAVA_HOME @echo off echo ADD java_home with JDK7 @set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_79 reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v JAVA_HOME /t REG_EXPAND_SZ /d "%JAVA_HOME%" /f pause
JDK8:
::删除环境变量JAVA_HOME @echo off echo Delete java_home set regpath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment set evname=JAVA_HOME reg delete "%regpath%" /v "%evname%" /f ::添加环境变量JAVA_HOME @echo off echo ADD java_home with JDK8 @set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_144 reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v JAVA_HOME /t REG_EXPAND_SZ /d "%JAVA_HOME%" /f pause
其实只有路径不一样,和一些提示语句。。
logger日志规范
使用占位符
logger.info("【出现异常{}】",e.toString());
需要关闭流的try-catch可以改为try-with-resources(JDK1.7+)
/**原本的写法**/
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
/**try-with-resources**/
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
List去除其中的null或者""值
// 去除空值 List<String> emptyList = new ArrayList<String>(); emptyList.add(null); emptyList.add(""); list.removeAll(emptyList);
合并List<Map<String,Object>>
/** * @Title: mergeListMap * @Description: 合并List<Map> * @param mapList1 * @param mapList2 * @param ID 公共ID部分 * @return 参数说明 * @return List<Map<String,Object>> 返回类型 */ public static List<Map<String, Object>> mergeListMap(List<Map<String, Object>> mapList1, List<Map<String, Object>> mapList2,String ID) { Map<String, Map<String, Object>> tempMap = new HashMap<>(); /**将mapList1分解为map**/ for (Map<String, Object> map : mapList1) { tempMap.put(map.get(ID).toString(), map); } /**将mapList2进行拆解**/ for (Map<String, Object> map : mapList2) { /**和tempMap中相同的ID**/ String sameID = map.get(ID).toString(); Map<String, Object> secondMap = tempMap.get(sameID); /**合并**/ secondMap.putAll(map); } return new ArrayList<Map<String, Object>>(tempMap.values()); }
全局StringBuilder
public class StringBuilderUtil {
private static final ThreadLocal<StringBuilderHelper> threadLocalStringBuilderHelper = new ThreadLocal<StringBuilderHelper>() {
@Override
protected StringBuilderHelper initialValue() {
return new StringBuilderHelper();
}
};
public static final StringBuilder getStringBuilder() {
return threadLocalStringBuilderHelper.get().getStringBuilder();
}
static final class StringBuilderHelper {
final StringBuilder sb;
StringBuilderHelper() {
sb = new StringBuilder();
}
StringBuilder getStringBuilder() {
sb.setLength(0);
return sb;
}
}
}
使用DruidDataSource直连数据库
获取数据时别名无效的情况
ResultSetMetaData转换成List的时候,
如果使用了getColumnName的话,会导致别名无效,可以改为:getColumnLabel
/**
* @Title: convertList
* @Description: 将ResultSet转换为List (借助ResultSetMetaData 和Map)
* @param rs
* @return
* @throws SQLException 参数说明
* @return List<Map<String, Object>> 返回类型
*/
private List<Map<String, Object>> convertList(ResultSet rs) throws SQLException {
List<Map<String, Object>> list = new LinkedList<>();
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
Map<String, Object> rowData = null;
while (rs.next()) {
rowData = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
rowData.put(md.getColumnLabel(i), rs.getObject(i)); //这里要设置成ColumnLabel才能识别别名
}
list.add(rowData);
}
return list;
}
批量插入
适用于仅数值不同的SQL,例子为Object[Object[]];
/**
* @Title: insertBatchForObjects
* @Description: 直连批量插入数据 ,用于Object数组中包含Object[]的插入
* @param sql
* @param param
* @throws Exception 参数说明
* @return void 返回类型
*/
public void insertBatchForObjects(String sql, Object[] param) throws Exception {
Connection conn = null;
PreparedStatement stmt = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
stmt = conn.prepareStatement(sql);
Object[] tempObjects = null;
for (Object objects : param) {
tempObjects = (Object[]) objects;
for (int i = 1, length = tempObjects.length; i <= length; i++) {
stmt.setObject(i, tempObjects[i - 1]);
}
stmt.addBatch();
}
stmt.executeBatch();
conn.commit();
stmt.clearBatch();
conn.setAutoCommit(true);
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
logger.error("occuring error:", e);
throw new BatchUpdateException(e);
} finally {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
抽象类
抽象类定义抽象方法由子类实现,在抽象类自己调用该抽象方法时,实际上是由子类实现的方法去实现
abstract class F { abstract String getSign(); void say(){ System.out.println(getSign()); } } class S extends F { @Override String getSign() { return "S类"; } } F f = new S(); f.say();
正则表达式-常用Mark
1.两个字符之间的字符串去除
([^ ]+?)\} //空格到下一个}之间的
([^#]+?)\! //#到下一个!之间的
ToString重写使用工具类:
@Override public String toString() { return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE); }
判断空用的工具类:
//判断StringisEmpty空格没有去除
org.apache.commons.lang.StringUtils.isBlank(str)
StringUtils.isNotBlank(str)
//判断Map
org.apache.commons.collections.MapUtils.isEmpty(map);
MapUtils.isNotEmpty(map);
//判断集合
org.apache.commons.collections.CollectionUtils.isEmpty(coll);
CollectionUtils.isNotEmpty(coll);
部署项目异常,代码没有显示报错,双Clean都不行。
Spring容器启动完毕后执行某个类中的方法
有时候想要在系统重启或者启动的时候得知某个类的方法运行结果,比如一个读取XML文件配置的参数类
有时候要到触发的时候才去读取,万一遇到忘记配置正确参数或者是读取参数异常的话。导致运行中的服务不能按正常流程走。
所以可以选择增加以下方法,启动的时候执行。一目了然。
public class ServiceConfig implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent arg0) { // dosomething like this showConfig(); } }
然后到spring-config.xml增加以下语句:
<!-- 当Spring容器启动完成后执行下面的这个Bean --> <bean class="com.XXX.ServiceConfig" />
重启后Spring初始化后会执行该段代码。稍微往上翻一点日志即可。
补充:如果该类已经纳入Spring的管理,如@Service、@Component
可以在static{}区域中添加方法(需要为静态)
或者使用注解@PostConstruct(普通方法即可)
BigDecimal的equals与compareTo的区别
对于BigDecimal的大小比较,用equals方法的话会不仅会比较值的大小,还会比较两个对象的精确度,而compareTo方法则不会比较精确度,只比较数值的大小。
System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20"))); //输出false System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //输出true System.out.println(new BigDecimal(1.2).equals(new BigDecimal("1.20"))); //输出是false System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal("1.20")) == 0); //输出是false System.out.println(new BigDecimal(1.2).equals(new BigDecimal(1.20))); //输出是true System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal(1.20)) == 0);//输出是true
工具包
除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的调用split,
可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
判断字符串、集合、Map是否为空。使用apache的工具类,如:
StringUtils.isEmpty(str); // 空字符串 StringUtils.isNotEmpty(str); StringUtils.isBlank(str); // 空白字符串 StringUtils.isNotBlank(str); CollectionUtils.isEmpty(coll); // 判断空集合(List) CollectionUtils.isNotEmpty(coll); MapUtils.isEmpty(map); // 判断空Map MapUtils.isNotEmpty(map);
将null字符串变成“”
阿里的fastjson
JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullStringAsEmpty);
Request和Response的优雅写法
// javax.servlet.http HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
Springboot配置文件读取
除了传统的注解,还可以使用类的注解,将配置项加载进来
例如配置文件中有个
test.model=true
@Component @ConfigurationProperties(prefix = "test",ignoreInvalidFields = false) public class ConfigClass { prviate boolean model = false; //后面是默认值 }
Spring类加载后执行一些方法
实现 InitializingBean 接口,重写afterPropertiesSet()
Filter中处理些业务
业务需要对一些信息进行Filter,首先是实现OncePerRequestFilter
业务处理不通过则需要返回,不再继续处理。
我们这边采用的是抛出异常,由于Filter中抛出的异常,要处理比较麻烦,所以直接对不通过的进行返回
public class XXXXFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 进行些业务处理
boolean status = true;
try{
// 具体业务处理,不通过则抛出异常,用以捕获
} catch (DiyException de){
handleException(response,de);
status = false;
}
if(status){
filterChain.doFilter(request, response);
}
}
}
void handleException(HttpServletResponse response,DiyException de){
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
Map<String,String> map = new HashMap<>();
map.put("code",de.getCode); // 自定义异常类中设置好Code
map.put("msg",de.getMsg); // 自定义异常类中设置好Msg
response.getWriter().print(JSONObject.toJSON(map));
}
Spring Boot 配置生效的顺序
1.Home 目录下的 Devtools 全局设置属性(~/.spring-boot-devtools.properties,当 devtools 激活时)。
2.测试用例上的 @TestPropertySource 注解。
3.测试用例上的 @SpringBootTest#properties 注解。
4.命令行参数。
5.来自 SPRING_APPLICATION_JSON 的属性(环境变量或系统属性中内嵌的内联 JSON )。
6.ServletConfig 初始化参数。
7.ServletContext 初始化参数。
8.来自于 java:comp/env 的 JNDI 属性。
9.Java 系统属性(System.getProperties())。
10.操作系统环境变量。
11.RandomValuePropertySource,仅包含 random.* 中的属性。
12.没有打进 jar 包的 Profile-specific 应用属性(application-{profile}.properties 和 YAML 变量)。
13.打进 jar 包中的 Profile-specific 应用属性(application-{profile}.properties 和 YAML 变量)。
14.没有打进 jar 包的应用配置(application.properties 和 YAML 变量)。
15.打进 jar 包中的应用配置(application.properties 和 YAML 变量)。
16.@Configuration 类上的 @PropertySource 注解。
17.默认属性(使用 SpringApplication.setDefaultProperties 指定)。
获取当前时间的String
public static void main(String[] args) { // yyyy-MM-dd HH:mm:ss.SSS ---> 年-月-日 时-分-秒-毫秒 String timeStr1=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); String timeStr2=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); System.out.println("当前时间为:"+timeStr1); System.out.println("当前时间为:"+timeStr2); }
当周的周一LocalDate today = LocalDate.now();
LocalDate toweekMonday = today.with(DayOfWeek.MONDAY);
浙公网安备 33010602011771号