avatar

正进一步

只有喜欢,才会全情投入,才会成功!!!

不关注架构设计细节的程序员不是一个好架构师

  • Home
  • Tags
  • Categories
  • Archives
  • 2018寄语
21用函数对象表示策略

实现函数对象的几种方式:

  • C语言的函数指针
  • lambda表达式
  • 函数式接口

函数对象主要用于策略模式.只用一次的话,使用匿名内部类;多次使用的话,可以导出成一个成员域(static final修饰)

实例:
java.util.Comparator

19接口只用于定义类型

当类实现接口时 ,接口就充当可以引用这个类的实例的类型(type)。因此,类实现了接口,就表明客户端可以对这个类的实例实施某些动作。为了任何其他目的而定义接口是不恰当的。

有一种接口被称为常量接口(constant interface),它不满足上述条件。这种接口没有方法,只有静态final域。常量接口模式是对接口的不良使用。这样做不仅会暴露该类的实现细节到导出API中,还会产生一个更糟糕的情况。就是在将来的发行版中,如果类不再需要使用这些常量,它依然必须实现这个接口,以确保二进制兼容性。如果非final类实现了常量接口,它的所有子类的命名空间也会被接口中的常量所“污染”。

反例

Java平台类库中有几个常量接口,例如java.io.ObjectStreamConstants。这些接口应该被认为是反面的典型,不值得效仿。

方案。

1.如果常量与某个现有类或接口紧密相关,就应该把这些常量添加到这个类或接口中。

2.如果这些常量可以被看作枚举类型的成员,就应该用枚举类型(enum type)。

3.用不可实例化的工具类( utility class)。使用静态导入(import static)避免常量修饰.

慎用可变参数
  • 至少传递一个
1
2
3
4
5
private static <E> void varargs(Object obj,E...varargs){
for(E e : varargs){
System.out.println(e);
}
}
  • 泛型编程只能接受引用类型

  • 打印数组tostring,会导致没有意义的字符结果

  • 可变参数每次调用都会导致有一次数组分配和初始化

  • EnumSet静态工厂最大限度地减少创建枚举集合的成本

1
2
3
4
5
6
7
public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
EnumSet<E> result = noneOf(first.getDeclaringClass());
result.add(first);
for (E e : rest)
result.add(e);
return result;
}
  • Arrays.toString(int[] args)可以打印数组,而不是可变参数
优先使用Lamdba,而不是匿名内部类
  • Lambda没有文档和名字,如果不能方法体太长或者不能自解释的话,那么就不要放到lamdba中。

  • Lambda不能使用this访问自身。this在Lambda是访问的外部类。如果要在方法体中访问自身的话,那么就不能使用Lambda

  • 不要在创建函数对象的时候使用匿名内部类,除非创建的对象不是函数式接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Operation {
PLUS ("+", (x, y) -> x + y),
MINUS ("-", (x, y) -> x - y),
TIMES ("*", (x, y) -> x * y),
DIVIDE("/", (x, y) -> x / y);
private final String symbol;
private final DoubleBinaryOperator op;
Operation(String symbol, DoubleBinaryOperator op) {
this.symbol = symbol;
this.op = op;
}
@Override public String toString() { return symbol; }
public double apply(double x, double y) {
return op.applyAsDouble(x, y);
}
}
66_同步访问共享的可变数量

当多个线程共享可变数据的时候,每个读取或者修改的线程都必须执行同步
Volatile保证读写都是原子的.
Long/Double读取非原子读取,volatile可以保证.

同步的作用:
  • 防止别的线程看到当前线程的中间的不一致状态
  • 保证前一线程修改的结果立即对当前线程可见.
第6条_消除过期的对象引用
  • 将数组中的不用的元素设置为null,尽早垃圾回收

  • 缓存可以使用WeakHashMap.及时将key进行回收。

  • 使用定时器将缓存中不用的项目删除或者LinkedHashMap.removeEldestEntry()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import com.alibaba.druid.support.json.JSONUtils;

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapTest {

private static final int MAX_ENTRIES =3;

public static void main(String[] args) {
LinkedHashMap<String,String> linkedHashMap =new LinkedHashMap(){
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
linkedHashMap.put("beijing","haid");
linkedHashMap.put("beijing2","haid2");
linkedHashMap.put("beijing3","haid3");
System.out.println(JSONUtils.toJSONString(linkedHashMap));
linkedHashMap.put("beijing4","haid4");
System.out.println(JSONUtils.toJSONString(linkedHashMap));
}
}

输出:

1
2
{"beijing":"haid","beijing2":"haid2","beijing3":"haid3"}
{"beijing2":"haid2","beijing3":"haid3","beijing4":"haid4"}

  • 将监听器回调及时的清除,可以使用WeakHashMap.

  • 使用内存Heap Profiler进行对象分析。

通过Builder模式降低参数数量,增加可读性

参考:http://www.importnew.com/6605.html

  • Builder会增加个类代码,这也意味着开发者在给类增加属性时有时会忘记给该属性添加支持的builder。为了克服这个问题,通常我会将builder嵌套到类中,这样可以很容易地发现哪个相关的builder需要更新

  • 构建对象时,如果碰到类有很多参数——其中很多参数类型相同而且很多参数可以为空时,我更喜欢Builder模式来完成。当参数数量不多、类型不同而且都是必须出现时,通过增加代码实现Builder往往无法体现它的优势。在这种情况下,理想的方法是调用传统的构造函数。再者,如果不需要保持不变,那么就使用无参构造函数调用相应的set方法吧。

  • 必要参数写到构造器里

  • 如果要实现builder的重用性,可以讲初始化工作放到目标类中。不需要重用的话,可以讲初始化工作在builde创建出来的时候,就将实例创建出来。

第4条_通过私有构造器强化不可实例化的能力

将构造器 设置为Private并且要抛出异常,就可以解决这个问题.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class UtilsClass {

//子类不能调用父类的构造方式,也就不能有子类了.
//抛出异常是为了 本类中 声明实例对象
private UtilsClass(){
throw new RuntimeException("不可以被初始化");
}

public static void main(String[] args) {

UtilsClass u =new UtilsClass();
System.out.println(u);

}
}
漫画之什么是CAS机制

转载自: https://mp.weixin.qq.com/s/f23I1kyJQoNPu6Ntrx0S6g

读后感:

Java1.6为Synchronized做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低. 这其中用到了CAS机制。

CAS优点

  • Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。
  • 避免了context switch

CAS缺点

  • CPU消耗较大,不适合高并发场景(因为冲突太多,失败率高)。
  • ABA问题
  • 不能保证代码块的原子性。例如不能保证多个变量同时更新.

乐观锁转悲观锁的经典代码见:ConcurrentHashMap的size方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public int size() {
// Try a few times to get accurate count. On failure due to
// continuous async changes in table, resort to locking.
final Segment<K,V>[] segments = this.segments;
int size;
boolean overflow; // true if size overflows 32 bits
long sum; // sum of modCounts
long last = 0L; // previous sum
int retries = -1; // first iteration isn't retry
try {
for (;;) {
if (retries++ == RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
ensureSegment(j).lock(); // force creation
}
sum = 0L;
size = 0;
overflow = false;
for (int j = 0; j < segments.length; ++j) {
Segment<K,V> seg = segmentAt(segments, j);
if (seg != null) {
sum += seg.modCount;
int c = seg.count;
if (c < 0 || (size += c) < 0)
overflow = true;
}
}
if (sum == last)
break;
last = sum;
}
} finally {
if (retries > RETRIES_BEFORE_LOCK) {
for (int j = 0; j < segments.length; ++j)
segmentAt(segments, j).unlock();
}
}
return overflow ? Integer.MAX_VALUE : size;
}
Java能修改Final类型变量吗_setAccessible_true

Field的public void setAccessible(boolean flag) 说明

   * Set the {@code accessible} flag for this object to
* the indicated boolean value.  A value of {@code true} indicates that
* the reflected object should suppress Java language access
* checking when it is used.  A value of {@code false} indicates
* that the reflected object should enforce Java language access checks.

如果flag设置为true,那么就会压制java语言的访问校验。

Java集合的稳定性(order)与有序性(sort)调研
引自于:http://atongyeye.iteye.com/blog/2358103

Java集合的稳定性(order)与有序性(sort)调研.
合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。 说明:

  1. 有序性是指遍历的结果是按某种比较规则依次排列的。

  2. 稳定性指集合每次遍历的元素次序是一定的。如:ArrayList,LinkedList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort.

微信勘误:try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
callMethod();
}
private static int callMethod() {
try {
System.out.println("call method");
return i();
}catch (Exception ex){

}finally {
System.out.println("finally block ");
}
return -1;
}
private static int i(){
System.out.println("i method");
return 1;
}

返回值

1
2
3
call method
i method
finally block