Item 1: Consider static factory methods instead of constructors

Item 2: Consider a builder when faced with many constructor parameters

Item 3: Enforce the singleton property with a private constructor

Item 4: Enforce noninstantiability with a private constructor Occasionally you’ll want to write a class that is just a grouping of static methods and static fields.

1
2
3
4
5
6
7
public class UtilityClass {
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
    ... // Remainder omitted
}

Item 5: Prefer dependency injection to hardwiring resources

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Bad, Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {
    private static final Lexicon dictionary = ...;

    private SpellChecker() {} // Noninstantiable

    public static boolean isValid(String word) { ... }
    public static List<String> suggestions(String typo) { ... }
}


// Good, Dependency injection provides flexibility and testability
public class SpellChecker {
    private final Lexicon dictionary;

    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }

    public boolean isValid(String word) { ... }
    public List<String> suggestions(String typo) { ... }
}

Item 6: Avoid creating unnecessary objects

Item 7: Eliminate obsolete object references 消除过时的对象引用

Item 8: Avoid finalizers and cleaners Finalizers are unpredictable, often dangerous, and generally unnecessary. As of Java 9, finalizers have been deprecated, but they are still being used by the Java libraries. The Java 9 replacement for finalizers is cleaners. Cleaners are less dangerous than finalizers, but still unpredictable, slow, and generally unnecessary.

Item 9: Prefer try-with-resources to try-finally

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
// Bad, try-finally is ugly when used with more than one resource!
static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            byte[] buf = new byte[BUFFERSIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

// Good, try-with-resources on multiple resources - short and sweet
static void copy(String src, String dst) throws IOException {
    try (InputStream   in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst)) {
        byte[] buf = new byte[BUFFERSIZE];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);
    }
}

Item 10: Obey the general contract when overriding equals Overriding the equals method seems simple, but there are many ways to get it wrong, and consequences can be dire. The easiest way to avoid problems is not to override the equals method, in which case each instance of the class is equal only to itself.

Item 11: Always override hashCode when you override equals You must override hashCode in every class that overrides equals. If you fail to do so, your class will violate the general contract for hashCode, which will prevent it from functioning properly in collections such as HashMap and HashSet.

Item 12: Always override toString providing a good toString implementation makes your class much more pleasant to use and makes systems using the class easier to debug

Item 13: Override clone judiciously

Item 14: Consider implementing Comparable

Item 15: Minimize the accessibility of classes and members make each class or member as inaccessible as possible

Item 16: In public classes, use accessor methods, not public fields

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Encapsulation of data by accessor methods and mutators
class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() { return x; }
    public double getY() { return y; }

    public void setX(double x) { this.x = x; }
    public void setY(double y) { this.y = y; }
}

Item 17: Minimize mutability

Item 18: Favor composition over inheritance Unlike method invocation, inheritance violates encapsulation

Item 19: Design and document for inheritance or else prohibit it the class must document its self-use of overridable methods

Item 20: Prefer interfaces to abstract classes

Item 21: Design interfaces for posterity ???

Item 22: Use interfaces only to define types

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Bad, Constant interface antipattern - do not use!
public interface PhysicalConstants {
    // Avogadro's number (1/mol)
    static final double AVOGADROSNUMBER   = 6.022140857e23;

    // Boltzmann constant (J/K)
    static final double BOLTZMANNCONSTANT = 1.38064852e-23;

    // Mass of the electron (kg)
    static final double ELECTRONMASS      = 9.10938356e-31;
}

// Good, Constant utility class
package com.effectivejava.science;

public class PhysicalConstants {
  private PhysicalConstants() { }  // Prevents instantiation

  public static final double AVOGADROSNUMBER = 6.022140857e23;
  public static final double BOLTZMANNCONST  = 1.38064852e-23;
  public static final double ELECTRONMASS    = 9.10938356e-31;
}

Item 23: Prefer class hierarchies to tagged classes

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Bad, Tagged class - vastly inferior to a class hierarchy!
class Figure {
    enum Shape { RECTANGLE, CIRCLE };

    // Tag field - the shape of this figure
    final Shape shape;

    // These fields are used only if shape is RECTANGLE
    double length;
    double width;

    // This field is used only if shape is CIRCLE
    double radius;

    // Constructor for circle
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    // Constructor for rectangle
    Figure(double length, double width) {
        shape = Shape.RECTANGLE;
        this.length = length;
        this.width = width;
    }

    double area() {
        switch(shape) {
          case RECTANGLE:
            return length * width;
          case CIRCLE:
            return Math.PI * (radius * radius);
          default:
            throw new AssertionError(shape);
        }
    }
}

// Good, Class hierarchy replacement for a tagged class
abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

    Circle(double radius) { this.radius = radius; }

    @Override double area() { return Math.PI * (radius * radius); }
}
class Rectangle extends Figure {
    final double length;
    final double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width  = width;
    }
    @Override double area() { return length * width; }
}

Item 24: Favor static member classes over nonstatic

Item 25: Limit source files to a single top-level class

1
2
3
4
5
6
7
8
// Two classes defined in one file. Don't ever do this!
class Utensil {
    static final String NAME = "pan";
}

class Dessert {
    static final String NAME = "cake";
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Good, Static member classes instead of multiple top-level classes
public class Test {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }

    private static class Utensil {
        static final String NAME = "pan";
    }

    private static class Dessert {
        static final String NAME = "cake";
    }
}

Item 26: Don’t use raw types

1
2
3
4
5
// Bad
private final Collection stamps = ... ;

// Parameterized collection type - typesafe
private final Collection<Stamp> stamps = ... ;

Item 27: Eliminate unchecked warnings Eliminate every unchecked warning that you can.

Item 28: Prefer lists to arrays

1
2
3
4
5
6
7
// Bad, Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException

// Good, Won't compile!
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");

Item 29: Favor generic types

1
2
Stack.java:8: generic array creation
        elements = new E[DEFAULTINITIALCAPACITY];
As explained in Item 28, you can’t create an array of a non-reifiable type, such as E.

Item 30: Favor generic methods

1
2
3
4
5
6
7
8
9
10
11
12
13
// Uses raw types - unacceptable! (Item 26)
public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    return result;
}

// Generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet<>(s1);
    result.addAll(s2);
    return result;
}

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable {
    final Segment<K,V>[] segments;
    static final int RETRIES_BEFORE_LOCK = 2;

    public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
        int sshift = 0;
        int ssize = 1;
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
        this.segmentShift = 32 - sshift;
        this.segmentMask = ssize - 1;
    }

    static final class HashEntry<K,V> {
        final int hash;
        final K key;
        volatile V value;
        volatile HashEntry<K,V> next;
    }

    private int hash(Object k) {
        int h = hashSeed;

        if ((0 != h) && (k instanceof String)) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

        // Spread bits to regularize both segment and index locations,
        // using variant of single-word Wang/Jenkins hash.
        h += (h <<  15) ^ 0xffffcd7d;
        h ^= (h >>> 10);
        h += (h <<   3);
        h ^= (h >>>  6);
        h += (h <<   2) + (h << 14);
        return h ^ (h >>> 16);
    }

    static final class Segment<K,V> extends ReentrantLock implements Serializable {
        transient volatile HashEntry<K,V>[] table;
        transient int count;
        // modify count
        transient int modCount;
        transient int threshold;
        final float loadFactor;

        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
            tryLock()
            // may rehash()
            unlock()
        }

        final V remove(Object key, int hash, Object value) {
            tryLock()
            unlock()
        }
    }

    public V get(Object key) {
        int h = hash(key);
        // Segment index
        (long)(((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE
        // Table index
        ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE
    }

    // Try RETRIES_BEFORE_LOCK times to get accurate count. On failure due to
    // continuous async changes in table, resort to LOCKING.    
    public int size() {
        // check segment.modCount to ensure accurate
        // but return sum of segment.count
    }

    public boolean isEmpty() {
        long sum = 0L;
        for (int j = 0; j < segments.length; ++j) {
            Segment<K,V> seg = segmentAt(segments, j);
            // if seg.count != 0, return false
            // else sum+=seg.modCount
        }

        // recheck unless no modifications
        for (int j = 0; j < segments.length; ++j) {
            //sum-=seg.modCount
        }
        if(sum != 0) return false;
        return true;
    }

    static {
        int ss, ts;
        UNSAFE = sun.misc.Unsafe.getUnsafe();
        Class tc = HashEntry[].class;
        Class sc = Segment[].class;
        TBASE = UNSAFE.arrayBaseOffset(tc);
        SBASE = UNSAFE.arrayBaseOffset(sc);
        ts = UNSAFE.arrayIndexScale(tc);
        ss = UNSAFE.arrayIndexScale(sc);
        SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
        TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
    }
}

Preface

I'm trying to do some integrations with jruby and java. I encountered some problems, and found that there were only a few information about jruby. So I write down my experience and share it.

Install JRuby

Environment: Mac, rvm

rvm get head
rvm install jruby-9.0.4.0

in your project folder, run

rvm use jruby-9.0.4.0

or create a .ruby-version file

echo 'jruby-9.0.4.0' > .ruby-version

Calling Java

create a folder named getting-started-with-jruby, you can find the code in Github

quick start

create a Hello.java

public class Hello {
    public static void world(){
        System.out.println("Hello JRuby!");
    }
}

compile it with javac Hello.java

require 'java' will give you access to any bundled Java libraries (classes within your java class path)

then we create a calling-class-in-root.rb

require 'java'
Java::Hello.world()

run ruby calling-class-in-root.rb in termial, and you will see the output. Hello JRuby!

Read on →

install bash-completion

1
brew install git bash-completion

add bash-completion to your .bash_profile

1
2
3
if [ -f `brew --prefix`/etc/bash_completion ]; then
    . `brew --prefix`/etc/bash_completion
fi

show branch name

1
2
3
4
parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "

References

  1. https://github.com/bobthecow/git-flow-completion/wiki/Install-Bash-git-completion
  2. http://martinfitzpatrick.name/article/add-git-branch-name-to-terminal-prompt-mac

_.iteratee = function(value, context, argCount) {}

1
2
3
4
5
6
7
8
9
// A mostly-internal function to generate callbacks that can be applied
// to each element in a collection, returning the desired result — either
// identity, an arbitrary callback, a property matcher, or a property accessor.
_.iteratee = function(value, context, argCount) {
  if (value == null) return _.identity;
  if (_.isFunction(value)) return createCallback(value, context, argCount);
  if (_.isObject(value)) return _.matches(value);
  return _.property(value);
};

_.iteratee的作用是生成callbacks,应用于collection的每个元素,返回分4种情况。

1) value == null

return _.identity

1
2
3
_.identity = function(value) {
  return value;
};

Example

1
2
3
4
> .identity('input value')
<- "input value"
> .iteratee(null)('input value')
<- "input value"

2) _.isFunction(value)

如果value为function, bind value(func) with context。 调用createCallback(value, context, argCount),return function(value, index, collection) {...}

3) _.isObject(value)

return _.matches(value) returns a predicate function.

4) else

return _.property(value)

Read on →

Yum Install PG9.4

1
2
3
4
5
wget http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-redhat94-9.4-1.noarch.rpm
yum instlal pgdg-redhat94-9.4-1.noarch.rpm
yum install postgresql94-server
service postgresql-9.4 initdb
chkconfig postgresql-9.4 on

Backup Data

1
2
su - postgres
pg_dumpall > dump.sql

Restore Data

1
2
3
4
service postgresql stop
service postgresql-9.4 start
su - postgres
psql < dump.sql

Config Network Access

vi /var/lib/pgsql/9.4/data/postgresql.conf

1
2
listen_addresses = '*'
port = 5432

/var/lib/pgsql/9.4/data/pg_hba.conf

1
2
3
4
5
6
7
8
# "local" is for Unix domain socket connections only
local   all         all                               ident
# IPv4 local connections:
host    all         all         127.0.0.1/32          ident
host    all         all         130.51.79.0/24        md5
host    all         all         10.210.29.0/24        md5
# IPv6 local connections:
host    all         all         ::1/128               ident

Remove PG8.4

1
2
yum remove postgresql
ln -s /usr/pgsql-9.4/bin/psql /usr/local/bin/psql

Refrences

  1. http://yum.postgresql.org/repopackages.php#pg94
  2. https://wiki.postgresql.org/wiki/YUM_Installation
  3. http://www.postgresql.org/docs/9.4/static/upgrading.html

1. Bundle a new gem

1
bundle gem jruby_gem

edit jrubygem.gemspec

1
2
3
4
Gem::Specification.new do |spec|
  ...
  spec.adddependency "jbundler"
end

Add TestUnit

1) edit jruby_gem.gemspec

1
2
3
4
Gem::Specification.new do |spec|
  ...
  spec.add_development_dependency "minitest"
end

2) edit RakeFile

Add test task code as below.

1
2
3
4
5
6
7
8
9
10
...
require 'rake/testtask'

Rake::TestTask.new do |t|
  t.libs << 'test'
  t.pattern = "test/*_test.rb"
end

desc "Run tests"
task :default => :test

3) create test/test_helper.rb

1
2
3
4
5
require 'jruby_gem'

require 'minitest/autorun'
require 'minitest/unit'
require 'minitest/pride'

Add Jar Dependency

edit jruby_gem.gemspec

1
2
3
4
Gem::Specification.new do |spec|
  ...
  spec.requirements << "jar 'jar-name', 'jar-version'"
end

Add Initializer

edit jrubygem/jrubygem.rb

2. In Rails App

edit Gemfile

1
gem 'jruby_gem', path: 'xxx'

1
2
3
touch Jarfile

jbunle

jbundle will read the requirements of jruby_gem.gemspec and then configure the classpath

Reference

  1. http://blakewilliams.me/blog/developing-gems-with-tdd-and-minitest-pt-1
  2. https://github.com/mkristian/jbundler/wiki/Gem-with-declared-jars
  3. https://github.com/richfisher/jruby_activiti

1. About Monit

Monit is a small Open Source utility for managing and monitoring Unix systems. Monit conducts automatic maintenance and repair and can execute meaningful causal actions in error situations.

2. Install Monit

1
2
3
yum install monit
chkconfig monit on
service monit start

3. Configure Monit Web Server

/etc/monit.d/monitrc

1
2
set httpd port 2812
  allow localhost

4. Configurations

1
2
3
4
5
6
7
8
check process httpd
  with pidfile /etc/httpd/run/httpd.pid
  start program = "/etc/init.d/httpd start"
  stop program = "/etc/init.d/httpd stop"
  if failed host localhost port 8081
  protocol http then restart
  if totalmem > 1024 MB for 2 cycles then restart
  if 5 restarts within 5 cycles then timeout
1
2
3
4
5
6
check process sidekiq
  with pidfile /var/your_app/shared/tmp/pids/sidekiq.pid
  start program = "/bin/bash -l -c 'cd /var/your_app/current && bundle exec sidekiq --index 0 --pidfile /var/your_app/shared/tmp/pids/sidekiq.pid --environment production --logfile /var/your_app/shared/log/sidekiq.log --daemon'"
  stop program = "/bin/bash -l -c 'cd /var/your_app/current && bundle exec sidekiqctl stop /var/your_app/shared/tmp/pids/sidekiq.pid 10'"
  if totalmem is greater than 512 MB for 3 cycles then restart
  if 3 restarts within 5 cycles then timeout
1
2
3
4
5
6
check process mysqld
  with pidfile /var/run/mysqld/mysqld.pid
  start program = "/etc/init.d/mysqld start"
  stop program = "/etc/init.d/mysqld stop"
  if failed host 127.0.0.1 port 3306 then restart
  if 5 restarts within 5 cycles then timeout
1
2
3
4
5
6
check process redis
  with pidfile /var/run/redis/redis.pid
  start program = "/etc/init.d/redis start"
  stop program = "/etc/init.d/redis stop"
  if failed host 127.0.0.1 port 6379 then restart
  if 5 restarts within 5 cycles then timeout

5. Reference

http://mmonit.com/monit/

http://railscasts.com/episodes/375-monit

1. Get Start

1
gem install selenium-webdriver

2. Basics Usage

1
2
@driver=Selenium::WebDriver.for :firefox
@wait = Selenium::WebDriver::Wait.new(:timeout => 10)
Navigate
1
@driver.navigate.to 'http://xx.xx.xx.xx'
Switch
1
2
3
4
5
@driver.switch_to.default_content

@driver.switch_to.frame('frame_id')

@driver.switch_to.window('window_id')
Find element
1
2
3
4
5
@driver.find_element(id: 'xxx')
@driver.find_element(name: 'xxx')
@driver.find_element(tag_name: 'xxx')
@driver.find_element(xpath: 'xxx')
@driver.find_element(css: 'xxx')
Click
1
2
el = @driver.find_element()
el.click
Double Click
1
2
el = @driver.find_element()
@driver.action.double_click(el).perform

3. Input

Text
1
2
find_displayed_element(name: 'element_name').clear
find_displayed_element(name: 'element_name').send_keys('123')
Select
1
2
3
4
el = find_displayed_element(name: field_name)
el.find_elements(tag_name: 'option').each_with_index do |option, index|
  option.click if option.text == 'target_text'
end

4. Common functions

1
2
3
4
5
def find_displayed_element(option)
  @wait.until { @driver.find_element(option) }
  @wait.until { @driver.find_element(option).displayed? }
  @driver.find_element(option)
end
1
2
3
4
5
6
def switch_to_displayed_frame(frame_id)
  find_displayed_element(id: frame_id)
  @driver.switch_to.frame(frame_id)

  @driver.execute_script("window.showModalDialog = window.open;");
end
1
2
3
4
5
6
7
8
9
def get_window_id_by_title(window_title)
  @wait.until { @driver.window_handles.size > 1 }

  wnd_titl = @driver.window_handles.map do |w|
    @driver.switch_to.window(w)
    [w, @driver.title]
  end
  win_id = wnd_titl.find{|e1,e2| e2 == window_title }.first
end

5. References

  1. http://docs.seleniumhq.org/
  2. https://code.google.com/p/selenium/wiki/RubyBindings

1. 下载

instant client 32bit www.oracle.com/technetwork/cn/topics/winsoft-085727.html‎

instant client 64bit www.oracle.com/technetwork/topics/winx64soft-089540.html

2. 解压

D:/instantclient121_32bit

D:/instantclient121_64bit

3. 添加环境变量

TNSADMIN D:/instantclient12164bit

4. 配置PL/SQL

D:/instantclient121_32bit/TNSNAMES.ORA

1
2
3
4
5
6
7
8
9
10
your_config_name =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = your_server_ip)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SID = your_sid)
      (SERVER = DEDICATED)
    )
  )

PL/SQL->Tools->Perferences->Oracle->Connection

Oracle Home=D:/instantclient12132bit OCILibrary=D:/instantclient121_32bit/oci.dll

5. 配置Navicat(64bit)

Navicat自带的oracle客户端有问题,需要手工指定路径。

Tools->Options->OCI

D:\instantclient121_64bit\oci.dll