只有光头才能变强java
前一阵子一直在学Redis,结果在黄金段位被虐了,暂时升不了段位了,天天都拿不到首胜(好烦)。git
趁着学校校运会,合理地给本身放了一个小长假,而后就回家了。回到家才发现当时618买了一堆书,这堆书还有没撕包装的呢....因而我翻出了最薄的一本《阿里巴巴 Java开发手册》程序员
这本书一共就90多页,一天就能够通读完了,看完以后我又来水博文了。github
注意:算法
PDF官方地址:sql
java.util.Object#equals
工具类Arrays.sort()或者Collections.sort()
会报异常。
/**内容*/
格式,不得使用 //xxx
方式///
来讲明注释代码的理由1、不容许任何魔法值(未经预先定义的常量)直接出如今代码中数据库
例子:编程
Negative example:
//Magic values, except for predefined, are forbidden in coding.
if (key.equals("关注公众号:Java3y")) {
//...
}
Positive example:
String KEY_PRE = "关注公众号:Java3y";
if (KEY_PRE.equals(key)) {
//...
}
复制代码
ps:我猜是把先常量定义出来,后续引用/修改的时候就很方便了。数组
2、Object的euqals方法容易抛出空指针异常,应使用常量或者有值的对象来调用equals。推荐使用java.util.Object#equals
工具类安全
java.util.Object#equals的源码(已经判断null的状况了)
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
复制代码
3、工具类Arrays.asList()把数组转成List时,不能使用其修改集合的相关方法。
由于返回的ArrayList是一个内部类,并无实现集合的修改方法。后台的数据还是数组,这里体现的是适配器模式。
4、在JDK7以及以上版本中,Comparator要知足自反性,传递性,对称性,否则调用Arrays.sort()或者Collections.sort()
会报异常。
The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)
The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.
Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.
反例:下例中没有处理相等的状况,实际使用中可能会出现异常:
new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getId() > o2.getId() ? 1 : -1;
}
}
复制代码
使用entrySet遍历Map类集合K/V,而不是用keySet方式遍历
首先咱们来看一下使用keySet是如何遍历HashMap的:
public static void main(String[] args) throws InterruptedException {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("关注公众号:", "Java3y");
hashMap.put("坚持原创", "Java3y");
hashMap.put("点赞", "关注,转发,分享");
// 获得keySet,遍历keySet获得全部的key
Set<String> strings = hashMap.keySet();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()) {
// HashMap的每一个key
String key = iterator.next();
// 经过key能够得到对应的value,若是有看过HashMap的同窗知道get方法的时间复杂度是O(1)
System.out.println("key = " + key + ", value = " + hashMap.get(key));
}
}
复制代码
再来看一下源码:
// 1. 获得keySet,若是不存在,则建立
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
// 2.初始化ks (实际上就是Set集合[HashMap的内部类],在初始化时须要顺便初始化iterator)
ks = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public K next() {
return i.next().getKey();
}
public void remove() {
i.remove();
}
};
}
};
复制代码
再来看一下entrySet,能够直接拿到key和value,不用再使用get方法来获得value,因此比keySet更加推荐使用!
public static void main(String[] args) throws InterruptedException {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("关注公众号:", "Java3y");
hashMap.put("坚持原创", "Java3y");
hashMap.put("点赞", "关注,转发,分享");
// 获得entrySet,遍历entrySet获得结果
Set<Map.Entry<String, String>> entrySet = hashMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}
}
复制代码
若是是JDK8的话,推荐直接使用Map.forEach()
就行了,咱们也来看看用法:
public static void main(String[] args) throws InterruptedException {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("关注公众号:", "Java3y");
hashMap.put("坚持原创", "Java3y");
hashMap.put("点赞", "关注,转发,分享");
// forEach用法
hashMap.forEach((key, value) -> System.out.println("key = " + key + ", value = " + value));
}
复制代码
其实在源码里边咱们能够发现,forEach实际上就是封装了entrySet,提供forEach给咱们能够更加方便地遍历Map集合
// forEach源码
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
复制代码
5、SimpleDateFormat是线程不安全的类,通常不要定义为static变量,若是定义为static,必须加锁,或者使用DateUtils工具类。
有如下的例子能够正确使用SimpleDateFormat:
// 1. 在方法内部使用,没有线程安全问题
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";
public String getFormat(Date date){
SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT);
return dateFormat.format(date);
}
// 2. 每次使用的时候加锁
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void getFormat(){
synchronized (SIMPLE_DATE_FORMAT){
SIMPLE_DATE_FORMAT.format(new Date());
….;
}
// 3. 使用ThreadLocal,每一个线程都有本身的SimpleDateFormat对象,互不干扰
private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
// 4. 使用DateTimeFormatter(This class is immutable and thread-safe.)
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(timeFormatter.format(LocalDateTime.now()));
复制代码
若是是JDK8应用,可使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat。
1、利用延迟关联或者子查询优化超多也分场景。
MySQL并非跳过 offset行,而是取 offset+N行,而后返回放弃前offset行,返回N行,那当 offset特别大的时候,效率就很是的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。
例子:
// 优化前
SELECT id, cu_id, name, info, biz_type
, gmt_create, gmt_modified, start_time, end_time, market_type
, back_leaf_category, item_status, picuture_url
FROM relation
WHERE biz_type = '0'
AND end_time >= '2014-05-29'
ORDER BY id ASC
LIMIT 149420, 20;
// 优化后
SELECT a.*
FROM relation a, (
SELECT id
FROM relation
WHERE biz_type = '0'
AND end_time >= '2014-05-29'
ORDER BY id ASC
LIMIT 149420, 20
) b
WHERE a.id = b.id
复制代码
解释:其实这里就是经过使用覆盖索引查询返回须要的主键,再根据主键关联原表得到须要的数据。这样就是充分利用了索引!
在看《手册》的时候还有一些知识点没看过、没实践过、涉及到的知识点比较多的,在这里先mark一下,后续再遇到或者有空的时候再回来补坑~
AtomicInteger count = new AtomicInteger(); count.addAndGet(1);
若是是 JDK8,推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减小乐观锁的重试次数)。固然了,若是你有比较好的资料阅读,也能够在评论区告诉我。我也会mark住好好看看。
好比说:“3y,我发现Optional类有篇文章写得很不错,url是xxxx(书籍的名称是xxx)
因为如今没有必定的经验积累,因此如下的章节得回头看:
看我上面写的内容就知道,除了一些规范外,还有不少实用的小技巧,这些对咱们开发是有帮助的。我这个阶段也有一些没怎么接触过的("日志","设计","二方库"),这些都须要我在成长中不断的回看才行。
引用书上的一句话:
不少编程方式客观上没有对错之分,一致性很重要,可读性很重要,团队沟通效率很重要。程序员天生须要团队协做,而协做的正能量要放在问题的有效沟通上。个性化应尽可能表如今系统架构和算法效率的提高上,而不是在合做规范上进行纠缠不休的讨论、争论,最后没有结论。
做者(孤尽)在知乎回答的一句话:
翻完了不表明记住了,记住了不表明理解了,理解了不表明可以应用上去,真正的知识是实践,实践,实践。
若是你以为我写得还不错,了解一下: