java 代碼

java 裏的 pandas

tablesaw
DataFrame
再有就是 spark 了css

java 代碼規範

java 阿里規範

Java8特性詳解 lambda表達式 Stream

Sonar 規則檢測

springboot官方

java有時間沒用就會容易生疏,這篇就來記錄本身平時java的練習

推薦啓動 jvm 時候 設置 classpath

java -cp all.jar  com.ghc.Main

觀察者模式

// 定義觀察者接口

public interface Observer {
    void callBack(String message,String name); // 調用MTB 接口發送數據過去
}

// 定義被觀察者接口 (壞人)
public interface BadGuy {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notice(String message);
}

// 觀察者實現類 警察 (其實這裏也能夠是線人因此定義 Observer 接口是有好處的)
public class Policeman implements  Observer {
    private String pName;
    Policeman(String pName){
        this.pName = pName;
    }
    @Override
    public void callBack(String message, String name) {
        System.out.println(this.pName+": "+name+" noticed:"+message);
    }
}


// 被觀察者 小偷(這裏也能夠是毒販 因此定義 BadGuy 接口的好處也是顯而易見的)

import java.util.concurrent.LinkedBlockingQueue;

public class Thief implements  BadGuy {
    private String name;
    Thief(String name){
        this.name = name;
    }
    private LinkedBlockingQueue<Observer> linkedBlockingQueue = new LinkedBlockingQueue<Observer>();
    @Override
    public void addObserver(Observer observer) {
        if(!linkedBlockingQueue.contains(observer)){
            try {
                linkedBlockingQueue.put(observer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void removeObserver(Observer observer) {
        if(linkedBlockingQueue.contains(observer)){
            linkedBlockingQueue.remove(observer);
        }
    }

    @Override
    public void notice(String message) {
        for(Observer observer:linkedBlockingQueue){
            observer.callBack(message,this.name);
        }
    }
}

//最後來個測試調用
public class ObserverDemo {

    public static void main(String [] args){
        Observer policeman = new Policeman("李警官");
        BadGuy thief = new Thief("小偷甲");
        thief.addObserver(policeman);
        thief.notice("那裏人傻錢多速來...");
    }
}

java 排序算法實現 待完善。。。

package com.middleplugin;

/*
* 這個類是一個演示類因此取名叫 Demo
* 主要演示循環與選擇分支以及數組這一重要容器的使用
* 涉及到常見排序算法:冒泡排序,快速排序*/
public class Demo {
    public static void main(String[] args){
        int [] array = {5,6,4,3,7,8,2};
        System.out.print("冒泡排序前的數組打印結果:");
        printArray(array); // 在排序以前打印數組 array
        bubbleSort(array);//冒泡排序
        quickSort(array,0,array.length-1); // 快速排序
        System.out.println(); //打印空行爲了
        System.out.print("冒泡排完序的數組打印結果:");
        printArray(array);// 在冒泡排序以後打印排好序的數組 array

        System.out.println("\n----===========我是華麗的分割線===========----");

        int [] secondArray = {5,6,4,3,7,8,2};
        System.out.print("快速排序前的數組打印結果:");
        printArray(secondArray); // 在排序以前打印數組 array
        quickSort(secondArray,0,secondArray.length-1); // 快速排序
        System.out.println(); //打印空行爲了
        System.out.print("快速排完序的數組打印結果:");
        printArray(secondArray);// 在冒泡排序以後打印排好序的數組 array
        System.out.println();
        String [] names = {"Frank","May","Tom","Jim"};
        for(String name:names){
            //遍歷 名字數組 names  注意這個是有 s 的
            System.out.println(name);
        }
    }

    // 這是一個格式化打印數組的方法,注意放在類裏通常叫方法而不講函數
    public static void printArray(int [] array){
        System.out.print("[");
        for(int i=0;i<array.length;i++){
            if(i!=array.length-1){
                System.out.print(array[i]+",");
            }
            else{
                System.out.print(array[i]+"]");
            }
        }
    }
    //交換數組值的方法
    public static void swapArray(int[] array,int i,int j){
        int temp = array[i];//使用第三方變量是經常使用的方法
        array[i] = array[j];
        array[j] = temp;
    }
    //冒泡排序算法的具體寫法
    public static void bubbleSort(int[] array){
        for(int i=0;i<array.length;i++){
            for(int j=0;j<array.length-1-i;j++){
                if(array[j]>array[j+1]){
                    swapArray(array,j,j+1);
                }
            }
        }
    }
    //快速排序算法,這個比較複雜一點,若是能夠,畫圖理解比較好,主要採起分治策略
    public static void quickSort(int[] array,int low,int high){
        if(low>=high){
            return; // 若是左邊的指針往右移超過或者等於了右邊的指針,那麼跳出遞歸
        }
        int left = low;
        int right = high;
        int baseValue = array[left];
        while(left<right){//開啓循環遞歸
            while(left<right&&array[right]>=baseValue){
                right--; //若是右邊指針左移 一直都是比基準值大或者相等的,則繼續左移
            }
            // 跳出了上面的循環,那麼意味着右邊指針找到比基準值小的數了,這時候填左邊坑
            array[left] = array[right];
            while(left<right&&array[left]<baseValue){
                left++; //同理,左邊指針右移 一直都是比基準值小的數字,則繼續右移
            }
            //跳出了上面的循環,那麼意味着左邊指針找到比基準值大的數字了,這時候填右邊坑
            array[right] = array[left];
            //一次循環結束,則要把基準值放入左邊坑
            array[left] = baseValue;

            //開啓遞歸
            quickSort(array,low,left-1);
            quickSort(array,left+1,high);

        }
    }
}

枚舉類型

public enum  WeekDayEnum {
    MONDAY("星期一"),TUESDAY("星期二"),WENDESDAY("星期三"),THURSDAY("星期四"),FRIDAY("星期五"),SATURDAY("星期六"),SUNDAY("星期日");
    private final String name;
    WeekDayEnum(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}
package com.ghc.hbase.api;

import java.util.Arrays;

public class Demo {
    public static void main(String[] args){
        WeekDayEnum weekDayEnum = WeekDayEnum.SATURDAY;
        System.out.println(weekDayEnum.getName());
        switch(weekDayEnum){
            case MONDAY:
                System.out.println(weekDayEnum.getName());
                break;
            case TUESDAY:
                System.out.println(weekDayEnum.getName());
                break;
            case SATURDAY:
            case SUNDAY:
                System.out.println("週末");
                break;
            default:
                System.out.println("略略略...");
                break;
        }
        // 這 函數式編程簡直上癮。。。
        Arrays.stream(WeekDayEnum.values()).forEach(System.out::println);
        Arrays.stream(WeekDayEnum.values()).forEach(e->System.out.println(e));
    }
}

/**
 * jdk8函數式接口,SAM類型的接口(Single Abstract Method)
 * 定義了這種類型的接口,使得以其爲參數的方法,能夠在調用時,使用一個lambda表達式做爲參數
 * 從SAM原則上講,這個接口中,只能有一個函數須要被實現,可是也能夠有以下例外:
 *     1. 默認方法與靜態方法並不影響函數式接口的契約,能夠任意使用,即函數式接口中能夠有靜態方法,
 *     一個或者多個靜態方法不會影響SAM接口成爲函數式接口,而且靜態方法能夠提供方法實現能夠由 default 修飾的默認方法方法,
 *     這個關鍵字是Java8中新增的,爲的目的就是使得某一些接口,原則上只有一個方法被實現,可是因爲歷史緣由,
 *     不得不加入一些方法來兼容整個JDK中的API,因此就須要使用default關鍵字來定義這樣的方法
 *  2. 能夠有 Object 中覆蓋的方法,也就是 equals,toString,hashcode等方法。
 * @author wind、

在java中函數式編程在兩個地方使用起來很方便,一個是匿名函數,一個是集合的stream操做。
只有一個方法的接口使用 @FunctionalInterface 註解那他就是 匿名函數
 *
 */

//函數式接口註解
@FunctionalInterface
interface AInterface{
    String getName(String name);
}

public class FunInterface {

   public static void testFun(AInterface a){
      System.out.println(a.getName("AAA"));
   }
   
   public static void main(String[] args) {
      //新方法
      AInterface a = (name) -> "hello " + name;
      System.out.println("a" + a.getName("world"));

      //老方法
      AInterface b = new AInterface() {
         @Override
         public String getName(String name) {
            return "hello " + name;
         }
      };
      System.out.println("b" + b.getName("world"));

      testFun(val -> "hello=" + val);
   }
   
}


// 幾乎已經中了 函數式的 毒

    private static boolean filterEven(int x){
        return x%2==0;
    }
    public static void main(String[] args){
        int [] indexes = {1,2,3,3,2,3,4,5,6,7};
        System.out.println(Arrays.stream(indexes).map(num->{return (int)(Math.random()*2)+num;}).distinct().filter(Demo::filterEven).reduce((x,y)->x+y).getAsInt());
    }

// 腦洞佛系排序大法,輕易不要用,被打了別怪我。。。
  public static void sortPrintArray(int[] array){
        Arrays.stream(array).forEach((n)->{new Thread(()->{
                                                            try{Thread.sleep(n);
                                                               System.out.println(n);
                                                              }catch(InterruptedException ie){
                                                                        ie.printStackTrace();}}
                                                     ).start();
                                            });
    }

通用接口返回優雅定義 (枚舉類(傳遞狀態碼與狀態信息)+泛型(傳遞數據))

/*枚舉類*/
package com.middleplugin.result;

public enum CodeMsg {
    SUCCESS("SUCCESS",200),FAILED("FAILED",500);
    private final String  name;
    private final int status;
    CodeMsg(String name,int status){
        this.name = name;
        this.status = status;
    }
    public String getName(){
        return this.name();
    }
    public int getStatus(){
        return this.status;
    }
    @Override
    public String toString(){
        return this.name+":"+this.status;
    }
}


/*封裝返回類 Result */
// --------------------==================---------------------
package com.middleplugin.result;

public class Result<T> {
    private String code;
    private int msg;
    private T data;

    public static <T> Result<T> success(T data){
        return new Result<T>(data);
    }
    public static <T> Result<T> error(){
        Result result = new Result<T>(null);
        result.code = CodeMsg.FAILED.getName();
        result.msg = CodeMsg.FAILED.getStatus();
        return result;
    }
    private Result(T data){
        this.data = data;
        this.code = CodeMsg.SUCCESS.getName();
        this.msg = CodeMsg.SUCCESS.getStatus();
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public int getMsg() {
        return msg;
    }

    public void setMsg(int msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

// controller 層調用,固然 正常狀況是丟到 catch exception 裏 Result.error() 的html

@RequestMapping(value="/Validate/GeneVariant3")
    @ResponseBody
    public Result<Boolean> GeneVariant3(@RequestBody String params){
        String  paramsStr = JSONObject.parseObject(params).getString("params");
        if(StringUtils.isEmpty(paramsStr)){
            return Result.error();
        }
        else{
            return Result.success(geneVariantDistinctService.isInvalidate(ValidateUtils.splitStr2List(paramsStr,",")));
        }
    }

@RestController是@ResponseBody + @Controller合體,當你在這個controller中方法只是想返回一個頁面時,就不能用@RestController,由於它會把你的返回值看成數據返回,而不是頁面名字,因此這時候就只能用@Controller。


若是mvn比較慢,建議更改maven目錄下的conf中的setting.xml,找到mirrors,在裏面加入這段話

     <id>nexus-aliyun</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>

構建最大堆

package com.ghc.starter.utils;

public class MaxHeapUtils {

    public static int [] array = {1,2,4,3,6,8,5,7,9,10};
    public static int heapSize = array.length;
    public static void main(String [] args){
        printArray(array);
        for(int i=heapSize/2;i>0;i--){
            maxHeapify(array,i);
        }
        printArray(array);
    }
    public static void printArray(int [] array){
        System.out.print("[");
        for(int i=0;i<array.length;i++){
            if(i!=heapSize-1){
                System.out.print(array[i]+",");
            }else{
                System.out.println(array[i]+"]");
            }
        }
    }
    public static void maxHeapify(int[] array,int rootIndx){
        int l = 2*rootIndx;
        int r = l+1;
        int largest;
        if(l<=heapSize && array[l-1]>array[rootIndx-1]){
            largest = l;
        }else{
            largest = rootIndx;
        }
        if(r<=heapSize && array[r-1] > array[largest-1]){
            largest = r;
        }
        // 只有當 largest 不是 index 時候才須要交換最大值與index所指向父節點的位置,而後遞歸調用該方法調整位置。
        if(largest!=rootIndx){
            swap(array,rootIndx-1,largest-1);
            // 這裏只有當 largest 沒超過 arrayLength/2 的時候遞歸纔有意義
            if(largest<=heapSize/2) {
                maxHeapify(array, largest);
            }
        }
    }
    public static void swap(int [] array,int i, int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

基礎

public class Demo {

    static{
        System.out.println("static code...");
    }
    public static void main(String [] args){
        new Demo().run();
        System.out.println("main code...");
    }

    {
        System.out.println("non-static code...");
    }
    public void run(){
        System.out.println("run code...");
    }
}
結果:
static code...
non-static code...
run code...
main code...

優化循環

for(int i=0, n=10;i<=n;i++){
            System.out.println(i);
        }
設置Mybatis打印調試sql的兩種方式
http://blog.csdn.net/gao36951/article/details/53641432

**************************************************

 

問題描述
在使用mybatis進行開發的時候,因爲能夠動態拼接sql,這樣大大方便了咱們。可是也有必定的問題,當咱們動態sql拼接的塊不少的時候,咱們要想從*mapper.xml中直接找出完整的sql就會很是的難,這個時候常常會須要把組合以後的完整sql調試出來比較好。下面來看兩種調試出sql的兩種方式

解決方案
方案1: 
網上說的比較多的,以前也是這麼用的一種方式 
1:首先將ibatis log4j運行級別調到DEBUG能夠在控制檯打印出ibatis運行的sql語句 
2:添加以下語句

按 Ctrl+C 複製代碼

###顯示SQL語句部分
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.Java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
按 Ctrl+C 複製代碼
 

方案2: 
最近發現的一種方式,方便快捷 
在mybatis.cfg.xml中增長以下配置

<settings>中增長
<setting name="logImpl" value="STDOUT_LOGGING" />
以上mybatis 調試出sql的兩種方式,Mark~~~

補充:

在spring boot 中,能夠配置application.properties

# --- {Logging}
logging.level.com.neusoft.newsroom=INFO
logging.level.org.springframework.security=INFO
logging.level.org.hibernate=ERROR
logging.level.com.mypackage.domain.persistence=DEBUG

Springboot + Druid 鏈接池

Druid是什麼?
       Druid是Java語言中最好的數據庫鏈接池。對於一個簡單的數據庫應用,因爲對於數據庫的訪問不是很頻繁。這時能夠簡單地在須要訪問數據庫時,就新建立一個鏈接,用完後就關閉它,這樣作也不會帶來什麼明顯的性能上的開銷。可是對於一個複雜的數據庫應用,狀況就徹底不一樣了。頻繁的創建、關閉鏈接,會極大的減低系統的性能,由於對於鏈接的使用成了系統性能的瓶頸。這個時候,咱們經過創建一個數據庫鏈接池以及一套鏈接使用管理策略,使得一個數據庫鏈接能夠獲得高效、安全的複用,避免了數據庫鏈接頻繁創建、關閉的開銷。

       那麼,咱們在springboot程序當中,如何配置druid數據庫鏈接池呢?

第一步:maven引入相應的jar包。


<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.5</version>
</dependency>
第二步:在resource下面,新增application.properties文件,添加數據庫的訪問配置



# 數據庫訪問配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=123456
# 下面爲鏈接池的補充設置,應用到上面全部數據源中
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置獲取鏈接等待超時的時間
spring.datasource.maxWait=60000
# 配置間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一個鏈接在池中最小生存的時間,單位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 配置監控統計攔截的filters,去掉後監控界面sql沒法統計,'wall'用於防火牆
spring.datasource.filters=stat,wall,log4j
spring.datasource.logSlowSql=true
第三步:因爲springboot程序的特性,咱們在工程的config包下面,建立DruidConfig.java文件,配置數據庫鏈接池。


第一種的配置方式:


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.StringUtils;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
import java.sql.SQLException;
import java.util.Arrays;
 
@Configuration
@EnableTransactionManagement
public class DuridConfig implements EnvironmentAware {
    private static final Logger logger = LoggerFactory.getLogger(DuridConfig.class);
 
    private Environment environment;
    private RelaxedPropertyResolver propertyResolver;
 
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        this.propertyResolver = new RelaxedPropertyResolver(environment, "spring.datasource.");
    }
 
    //註冊dataSource
    @Bean(initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() throws SQLException {
        if (StringUtils.isEmpty(propertyResolver.getProperty("url"))) {
            System.out.println("Your database connectio n pool configuration is incorrect!"
                    + " Please check your Spring profile, current profiles are:"
                    + Arrays.toString(environment.getActiveProfiles()));
            throw new ApplicationContextException(
                    "Database connection pool is not configured correctly");
        }
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(propertyResolver.getProperty("driver-class-name"));
        druidDataSource.setUrl(propertyResolver.getProperty("url"));
        druidDataSource.setUsername(propertyResolver.getProperty("username"));
        druidDataSource.setPassword(propertyResolver.getProperty("password"));
        druidDataSource.setInitialSize(Integer.parseInt(propertyResolver.getProperty("initialSize")));
        druidDataSource.setMinIdle(Integer.parseInt(propertyResolver.getProperty("minIdle")));
        druidDataSource.setMaxActive(Integer.parseInt(propertyResolver.getProperty("maxActive")));
        druidDataSource.setMaxWait(Integer.parseInt(propertyResolver.getProperty("maxWait")));
        druidDataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(propertyResolver.getProperty("timeBetweenEvictionRunsMillis")));
        druidDataSource.setMinEvictableIdleTimeMillis(Long.parseLong(propertyResolver.getProperty("minEvictableIdleTimeMillis")));
        druidDataSource.setValidationQuery(propertyResolver.getProperty("validationQuery"));
        druidDataSource.setTestWhileIdle(Boolean.parseBoolean(propertyResolver.getProperty("testWhileIdle")));
        druidDataSource.setTestOnBorrow(Boolean.parseBoolean(propertyResolver.getProperty("testOnBorrow")));
        druidDataSource.setTestOnReturn(Boolean.parseBoolean(propertyResolver.getProperty("testOnReturn")));
        druidDataSource.setPoolPreparedStatements(Boolean.parseBoolean(propertyResolver.getProperty("poolPreparedStatements")));
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(Integer.parseInt(propertyResolver.getProperty("maxPoolPreparedStatementPerConnectionSize")));
        druidDataSource.setFilters(propertyResolver.getProperty("filters"));
        logger.info("DuridConfig-----數據源完成");
        return druidDataSource;
    }
 
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
//        //mybatis分頁
//        PageHelper pageHelper = new PageHelper();
//        Properties props = new Properties();
//        props.setProperty("dialect", "mysql");
//        props.setProperty("reasonable", "true");
//        props.setProperty("supportMethodsArguments", "true");
//        props.setProperty("returnPageInfo", "check");
//        props.setProperty("params", "count=countSql");
//        pageHelper.setProperties(props);
//        //添加插件
//        sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
        //添加XML目錄
        VFS.addImplClass(SpringBootVFS.class);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        logger.info("dao層掃描包爲:mapper/*.xml");
        return sqlSessionFactoryBean.getObject();
    }
 
    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(dataSource());
 
    }
 
 
}
第二種的配置方式:


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.github.pagehelper.PageHelper;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;
 
/**
 *                             _ooOoo_
 *                            o8888888o
 *                            88" . "88
 *                            (| -_- |)
 *                            O\  =  /O
 *                         ____/`---'\____
 *                       .'  \\|     |//  `.
 *                      /  \\|||  :  |||//  \
 *                     /  _||||| -:- |||||-  \
 *                     |   | \\\  -  /// |   |
 *                     | \_|  ''\---/''  |   |
 *                     \  .-\__  `-`  ___/-. /
 *                   ___`. .'  /--.--\  `. . __
 *                ."" '<  `.___\_<|>_/___.'  >'"".
 *               | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *               \  \ `-.   \_ __\ /__ _/   .-` /  /
 *          ======`-.____`-.___\_____/___.-`____.-'======
 *                             `=---='
 *          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *                     佛祖保佑        永無BUG
 *            佛曰:
 *                   寫字樓裏寫字間,寫字間里程序員;
 *                   程序人員寫程序,又拿程序換酒錢。
 *                   酒醒只在網上坐,酒醉還來網下眠;
 *                   酒醉酒醒日復日,網上網下年復年。
 *                   希望老死電腦間,不肯鞠躬老闆前;
 *                   奔馳寶馬貴者趣,公交自行程序員。
 *                   別人笑我忒瘋癲,我笑本身命太賤;
 *                   不見滿街漂亮妹,哪一個歸得程序員?
 */
@Configuration
@EnableTransactionManagement
public class DruidConfig {
 
    private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
 
 
    @Value("${spring.datasource.url}")
    private String dbUrl;
 
    @Value("${spring.datasource.username}")
    private String username;
 
    @Value("${spring.datasource.password}")
    private String password;
 
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
 
    @Value("${spring.datasource.initialSize}")
    private int initialSize;
 
    @Value("${spring.datasource.minIdle}")
    private int minIdle;
 
    @Value("${spring.datasource.maxActive}")
    private int maxActive;
 
    @Value("${spring.datasource.maxWait}")
    private int maxWait;
 
    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;
 
    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;
 
    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;
 
    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;
 
    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;
 
    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;
 
    @Value("${spring.datasource.filters}")
    private String filters;
 
    @Value("${spring.datasource.logSlowSql}")
    private String logSlowSql;
 
    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");
        reg.addInitParameter("loginUsername", username);
        reg.addInitParameter("loginPassword", password);
        reg.addInitParameter("logSlowSql", logSlowSql);
        return reg;
    }
 
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        return filterRegistrationBean;
    }
 
    @Bean
    public DataSource druidDataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter", e);
        }
        return datasource;
    }
 
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(druidDataSource());
        //mybatis分頁
        PageHelper pageHelper = new PageHelper();
        Properties props = new Properties();
        props.setProperty("dialect", "mysql");
        props.setProperty("reasonable", "true");
        props.setProperty("supportMethodsArguments", "true");
        props.setProperty("returnPageInfo", "check");
        props.setProperty("params", "count=countSql");
        pageHelper.setProperties(props);
        //添加插件
       sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
        //添加XML目錄
        VFS.addImplClass(SpringBootVFS.class);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
        logger.info("dao層掃描包爲:mapper/*.xml");
        return sqlSessionFactoryBean.getObject();
    }
 
    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(druidDataSource());
 
    }
 
 
 
 
 
}
須要的jar包的信息都包含在import信息當中。

經過以上的三步操做,咱們就已經配置好了JAVA當中最好的數據庫鏈接池了。
使用阿里雲代碼規範插件掃描後出現如下提示:

hashmap should set a size when initalizing,即hashmap應該在初始化時設置一個大小

在網上搜到一篇講解(https://www.cnblogs.com/coderxuyang/p/3718856.html),以下:


在元素的裝載數量明確的時候HashMap的大小應該如何選擇。
今天看到美團招聘給出了一道小題目,關於HashMap的性能問題。問題以下:

java hashmap,若是肯定只裝載100個元素,new HashMap(?)多少是最佳的,why?

要回答這個問題,首先得知道影響HashMap性能的參數有哪些。我們翻翻JDK。

在JDK6中是這麼描述的:

HashMap的實例有兩個參數影響其性能:初始容量和加載因子。

首先咱們來看初始容量和加載因子的定義。

容量是哈希表中桶的數量,初始容量只是哈希表在建立時的容量。

加載因子是哈希表在其容量自動增長以前能夠達到多滿的一種尺度。

當哈希表中條目的數目超過 容量乘加載因子 的時候,則要對該哈希表進行rehash操做,從而哈希表將具備大約兩倍的桶數。(以上摘自JDK6)

HashMap默認的加載因子是0.75 .它在時間和空間成本上尋求了一種折中。

 

回到本文的問題。根據JDK中的描述,若是這個只裝載100個元素的HashMap沒有特殊的用途,那麼爲了在時間和空間上達到最佳性能,HashMap的初始容量能夠設爲

100/0.75 = 133.33。爲了防止rehash,向上取整,爲134。

 

可是還有另一個問題,就是hash碰撞的問題。若是咱們將HashMap的容量設置爲134,那麼如何保證其中的哈希碰撞會比較少呢?

除非重寫hashcode()方法,不然,彷佛沒有辦法保證。

那麼這裏不得不提HashMap如何爲元素選擇下標的方法了。

    static int indexFor(int h, int length) {
        return h & (length-1);
    }
其中h爲key哈希後獲得的值,length爲哈希表的長度。

134-1 = 128 + 6 -1;

那麼 length-1的二進制值的最後3位爲101;

假設這100個裝載的元素中他們的key在哈希後有獲得兩個值(h),他們的二進制值除了低3位以外都相同,而第一個值的低3位爲011,第二個值的低3位爲001;

這時候進行java的&預算,011 & 101 = 001 ;001 & 101 = 001;

他們的值相等了,那麼這個時候就會發生哈希碰撞。

除此以外還有一個更加嚴重的問題,因爲在101中第二位是0,那麼,不管咱們的key在哈希運算以後獲得的值h是什麼,那麼在&運算以後,獲得的結果的倒數第二位均爲0;

所以,對於hash表全部下標的二進制的值而言,只要低位第二位的值爲1,(例如0010,0011,0111,1111)那麼這個下標所表明的桶將一直是空的,由於代碼中的&運算的結果永遠不會產生低位第二位爲1的值。這就大大地浪費了空間,同時還增長了哈希碰撞的機率。這無疑會下降HashMap的效率。

那麼如何才能減小這種浪費呢?最佳的方法固然是讓length-1的二進制值所有位均爲1.那麼length的值是多少合適呢?

沒錯,length=2^n。

只要將hash表的長度設爲2的N次方,那麼,全部的哈希桶均有被使用的可能。

再次回到美團提出的問題,與134最靠近的2^n無疑是128。

若是隻修改HashMap的長度而不修改HashMap的加載因子的話,HashMap會進行rehash操做,這是一個代價很大的操做,因此不可取。

那麼應該選擇的就應該是256。

而因爲空間加大和有效利用哈希桶,這時的哈希碰撞將大大下降,所以HashMap的讀取效率會比較高。

 

因此,最後結論就是:HashMap的大小應該設置爲256。

 

結果的補充:其實在Java中,不管你的HashMap(x)中的x設置爲多少,HashMap的大小都是2^n。2^n是大於x的第一個數。由於HashMap的初始化代碼中有如下這行代碼:

 int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;
可是這就帶來了一個問題,若是x=100,那麼HashMap的初始大小應該是128.可是100/128=0.78,已經超過默認加載因子(0.75)的大小了。所以會resize一次,變成256。因此最好的結果仍是256。

最後發個參考連接:http://www.iteye.com/topic/539465

另,總結StringBuffer、ArrayList、HashMap的擴容:

StringBuffer:內部實現是一個字符數組。初始默認大小爲16,固然也能夠在其構造方法中進行設置。當新添加字符或字符串時,發現數組容量不夠。這個時候就須要使用Array.copyOf()方法進行擴充。擴充的新的數組大小等於,(原始容量*2+2)和(數組實際字符個數+新增的字符長度)之間的較大值。

ArrayList:內部實現是一個Object的數組。初始默認大小爲0,固然也能夠在其構造方法中設置。當添加一個Object時,默認擴充數組容量爲10。而後每次擴充的新的數組大小等於,(原始容量*3/2)和(數組的長度+1)之間的較大值。根據每次增長一個Object,可得該狀況每次擴充的固定大小爲3/2。當初始大小爲手動設置的時候,每次擴充的新的數組大小等於,(原始容量*3/2)和(數組的長度+1)之間的較大值。

HashMap:內部實現是一個Entry的數組,默認大小是空的數組。初始化的容量是16,加載因子是3/4(當數組元素數量大於總容量的加載因子的時候,擴充數組)。當默認不是空的數組時,當達到加載因子的比例的時候,每次擴充初始容量的2倍。

自定義註解使用

import java.lang.annotation.*;

//元註解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {

    String desc();
    String author();

    int age() default 18;
}


// interface 其實 不會起做用應該 換成 class 
public interface Person {
    @Description(desc="eat",author = "Frank",age=20)
    void eat();
    void run();
    @Deprecated
    void sing();
}


        Class c = Class.forName("com.ghc.hbase.api.Person");
        boolean isExist = c.isAnnotationPresent(Description.class);
        if(isExist){
            Description d = (Description) c.getAnnotation(Description.class);
            System.out.println(d.desc());
        }

        Method[] methods = c.getMethods();
        for(Method m:methods){
            boolean isExistOnMethod = m.isAnnotationPresent(Description.class);
            if(isExistOnMethod){
                Description d = (Description)m.getAnnotation(Description.class);
                System.out.println(d.age());
            }
        }

        for(Method m:methods){
            Annotation[] annotations = m.getAnnotations();
            for(Annotation annotation:annotations){
                if(annotation instanceof Description){
                    ((Description) annotation).author();
                }
            }
        }

使用 數組 繞過 lambda 表達式 跟 匿名函數不能在內部 修改 外部變量的問題

Integer variantImpact;
        final int[] variantImpactArray = new int[1];
        VariantImpactEnum.getMap().keySet().forEach(key->{
            if(features.contains(key)){
                variantImpactArray[0] = VariantImpactEnum.getMap().get(key);
            }
        });
        variantImpact = variantImpactArray[0];

集合操做排序 重複值問題

import java.util.Objects;

/**
 * @author :Frank Li
 * @date :Created in 2019/7/3 9:48
 * @description:${description}
 * @modified By:
 * @version: $version$
 */
public class Student {
    private String name;
    private String gender;
    private int age;

    Student(String name, String gender, int age){
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    @Override
    public boolean equals(Object obj){
        if(this == obj) return true;
        if(!(obj instanceof Student)) return false;
        Student that = (Student) obj;
        return Objects.equals(this.name,that.name) && Objects.equals(this.gender,that.gender) && this.age==that.age;
    }

    @Override
    public int hashCode(){
        return Objects.hash(this.name,this.gender,this.age);
    }
    public String getName() {
        return name;
    }

    
    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append(this.name)
                .append("|")
                .append(this.gender)
                .append("|")
                .append(this.age);
        return sb.toString();
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}



import java.util.*;

/**
 * @author :Frank Li
 * @date :Created in 2019/7/3 9:22
 * @description:${description}
 * @modified By:
 * @version: $version$
 */
public class Demo {

    public static void main(String [] args){
        Set<Student> personSet = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return (o1.getAge()-o2.getAge());
            }
        });
        Student s1 = new Student("a","f",18);
        Student s2 = new Student("b","m",19);
        Student s3 = new Student("c","f",20);
        Student s4 = new Student("c","f",20);
        personSet.add(s1);
        personSet.add(s2);
        personSet.add(s3);
        personSet.add(s4);

        for(Student s:personSet){
            System.out.println(s);
        }

        System.out.println("**********");

        List<Student> studentList = new ArrayList<Student>(5);
        studentList.add(s1);
        studentList.add(s2);
        studentList.add(s3);
        studentList.add(s4);

Collections.sort(studentList, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return -(o1.getAge() - o2.getAge());
            }
        });

        System.out.println(studentList.toString());

        for(Student s: dropDuplicateList(studentList)){
            System.out.println(s);
        }


    }

    public static <T extends Student>  List<T> dropDuplicateList(List<T> inputList){
        Set<T> dropDupSet = new TreeSet<T>(new Comparator<T>() {
            @Override
            public int compare(T o1, T o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        dropDupSet.addAll(inputList);
        return new ArrayList<T>(dropDupSet);
    }
}


//  優先級隊列

Queue<Student> queue = new PriorityQueue<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return - (o1.getAge() - o2.getAge());
            }
        });
        queue.add(new Student("a","f",18));
        queue.add(new Student("b","m",19));
        queue.add(new Student("c","f",20));

        for(int i=0, n=queue.size();i<n;i++){
            Student s = queue.poll();
            System.out.println(s);
        }

// 雙向隊列

   public static void main(String [] args){
        Deque<Student> deque = new LinkedList<Student>();
        Student s1 = new Student("a","f",18);
        Student s2 = new Student("b","m",19);
        Student s3 = new Student("c","f",20);

        deque.addFirst(s2);
        deque.addLast(s3);
        deque.addFirst(s1);

        for(int i=0, n=deque.size();i<n;i++){
            Student s = deque.pollLast();
            System.out.println(s);
        }
    }

經常使用工具類

public static void main(String [] args){
        System.out.println(getRange(10,100).intValue());
    }

    public static Number getRange(int min, int max){
        return Math.random()*(max-min)+min;
    }

斷言, IDE 中 配置 -ea:com.ghc.Demo

public static void main(String [] args){
        System.out.println(getRange(10,100).intValue());
        int randInt = 9; //getRange(10,100).intValue();
        assert randInt >= 10 && randInt <100 : "rand Int should between "+10+" and "+100+" but randInt ="+randInt;
    }

    public static Number getRange(int min, int max){
        return Math.random()*(max-min)+min;
    }

等待研究 連接

Serializable
Transient
Vilotile
JVM
或許是慣性思惟,在mybatis使用foreach循環調用的時候,不少時候都是傳一個對象,傳一個List的狀況不多,因此寫代碼有時候會不注意就用慣性思惟方法作了。
今天向sql傳參,傳了一個List做爲參數,而後在xml裏再foreach循環調用。而後報錯信息如:

mybatis foreach報錯It was either not specified and/or could not be found for the javaType
Type handler was null on parameter mapping for property '__flowStepCode_0

Mapper接口

List<AllocationHandlerInfoVo> listAllocatedHandlerInfo(@Param("flowStepCodeList")List<ApprStepModel> flowStepCodeList);
原來是這樣:#{flowStep},處理方法,換成#{flowStep.flowStepCode},List是個集合來的,要注意,寫博客記錄

 <if test="flowStepCodeList != null and flowStepCodeList.size() > 0">
             fh.flow_step_code in
            <foreach collection="flowStepCodeList" item="flowStep" index="index" open="(" close=")" separator=",">
                        #{flowStep.flowStepCode}
            </foreach>              
</if>

Map & Set 判斷 元素是否相等 調用 hashCode + equals 方法一塊兒

import java.util.HashMap;
import java.util.Map;

public class Person {
    private String name;
    private int age=0;
    private String sex;
    @Override
    public int hashCode(){
        return this.age;
    }
    public boolean equals(Object obj){
        Person person = (Person) obj;
        return this.name == person.name;
    }
    public Person(String name, int age, String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public static void main(String [] args){
        Map map = new HashMap();
        Person p1 = new Person("王恆定",20,"男");
        Person p2 = new Person("劉炎",20,"女");
        Person p3 = new Person("陳世陽",25,"女");
        Person p4 = new Person("劉炎",20,"男");
        map.put(p1,"教師");
        map.put(p2,"特級教師");
        map.put(p3,"教師");
        map.put(p4,"高級教師");
        System.out.println(map.size());
        System.out.println(p2 == p4);
        System.out.println(p2.equals(p4));
        System.out.println(map.get(p2));
        System.out.println(map.get(p4));
    }
}

// 結果 p4 替換了 p2
正例:(涉及1-5點)
public static void main(String args[]) {
    //縮進4個空格
    String say = "hello";
    //運算符的左右必須有一個空格
    int flag = 0;
    //關鍵詞if與括號之間必須有一個空格,括號內的f與左括號,0與右括號不須要空格
    if (flag == 0) {
        System.out.println(say);
    }
    //左大括號前加空格且不換行;左大括號後換行
    if (flag == 1) {
        System.out.println("world");
        //右大括號前換行,右大括號後有else,不用換行
    } else {
        System.out.println("ok");
        //在右大括號後直接結束,則必須換行
    }
}

import java.util.Objects;
使用 Objects.equals(obj1, obj2); // 來避免 equals 的問題

19.*【推薦】*慎用Object的clone方法來拷貝對象。

說明:對象的clone方法默認是淺拷貝,若想實現深拷貝須要重寫clone方法實現屬性對象的拷貝。

【推薦】*類成員與方法訪問控制從嚴:

若是不容許外部直接經過new來建立對象,那麼構造方法必須是private。
工具類不容許有public或default構造方法。
類非static成員變量而且與子類共享,必須是protected。
類非static成員變量而且僅在本類使用,必須是private。
類static成員變量若是僅在本類使用,必須是private。
如果static成員變量,必須考慮是否爲final。
類成員方法只供類內部調用,必須是private。
類成員方法只對繼承類公開,那麼限制爲protected
說明:任何類、方法、參數、變量,嚴控訪問範圍。過寬泛的訪問範圍,不利於模塊解耦。

思考:若是是一個private的方法,想刪除就刪除,但是一個public的Service方法,或者一個public的成員變量,刪除一下,不得手心冒點汗嗎?變量像本身的小孩,儘可能在本身的視線內,變量做用域太大,若是無限制的處處跑,那麼你會擔憂的。

1.**【強制】**關於hashCode和equals的處理,遵循以下規則:

只要重寫equals,就必須重寫hashCode。
由於Set存儲的是不重複的對象,依據hashCode和equals進行判斷,因此Set存儲的對象必須重寫這兩個方法。
若是自定義對象作爲Map的鍵,那麼必須重寫hashCode和equals。
正例:String重寫了hashCode和equals方法,因此咱們能夠很是愉快地使用String對象做爲key來使用。

List<String> myList = new ArrayList<String>();
       myList.add("a");
       myList.add("b");
       myList.add("c");
       System.out.println(myList.subList(2,3) instanceof ArrayList);//false
       System.out.println(myList.subList(2,3) instanceof List);//true

在subList場景中,高度注意對原集合元素個數的修改,會致使子列表的遍歷、增長、刪除均產生ConcurrentModificationException異常。

【強制】**使用集合轉數組的方法,必須使用集合的toArray(T[] array),傳入的是類型徹底同樣的數組,大小就是list.size()。

反例:直接使用toArray無參方法存在問題,此方法返回值只能是Object[]類,若強轉其它類型數組將出現ClassCastException錯誤。
正例:
List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);
說明:使用toArray帶參方法,入參分配的數組空間不夠大時,toArray方法內部將從新分配
內存空間,並返回新數組地址;若是數組元素大於實際所需,下標爲[ list.size() ]的數組
元素將被置爲null,其它數組元素保持原值,所以最好將方法入參數組大小定義與集合元素
個數一致。

【強制】**使用工具類Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法,它的add/remove/clear方法會拋出UnsupportedOperationException異常。

說明:asList的返回對象是一個Arrays內部類,並無實現集合的修改方法。Arrays.asList體現的是適配器模式,只是轉換接口,後臺的數據還是數組。

String[] str = new String[] { "a", "b" };
List list = Arrays.asList(str);
第一種狀況:list.add("c");運行時異常。
第二種狀況:str[0]= "gujin";那麼list.get(0)也會隨之修改。

【強制】**泛型通配符<? extends T>來接收返回的數據,此寫法的泛型集合不能使用add方法。

說明:蘋果裝箱後返回一個<? extends Fruits>對象,此對象就不能往裏加任何水果,包括蘋果。

9.*【推薦】*集合初始化時,儘可能指定集合初始值大小。

說明:ArrayList儘可能使用ArrayList(int initialCapacity)初始化。

10.*【推薦】*使用entrySet遍歷Map類集合KV,而不是keySet方式進行遍歷。

說明:keySet實際上是遍歷了2次,一次是轉爲Iterator對象,另外一次是從hashMap中取出key所對應的value。而entrySet只是遍歷了一次就把key和value都放到了entry中,效率更高。若是是JDK8,使用Map.foreach方法。

正例:values()返回的是V值集合,是一個list集合對象;keySet()返回的是K值集合,是一個Set集合對象;entrySet()返回的是K-V值組合集合。

11.*【推薦】*高度注意Map類集合K/V能不能存儲null值的狀況,以下表格:

集合類 Key Value   Super   說明
Hashtable   不容許爲null    不容許爲null    Dictionary  線程安全
ConcurrentHashMap   不容許爲null    不容許爲null    AbstractMap 分段鎖技術
TreeMap 不容許爲null    容許爲null AbstractMap 線程不安全
HashMap 容許爲null 容許爲null AbstractMap 線程不安全
反例:因爲HashMap的干擾,不少人認爲ConcurrentHashMap是能夠置入null值,注意存儲null值時會拋出NPE異常。
12.【參考】合理利用好集合的有序性(sort)和穩定性(order),避免集合的無序性(unsort)和不穩定性(unorder)帶來的負面影響。

說明:穩定性指集合每次遍歷的元素次序是必定的。有序性是指遍歷的結果是按某種比較規則依次排列的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是order/sort。

13.【參考】利用Set元素惟一的特性,能夠快速對一個集合進行去重操做,避免使用List的contains方法進行遍歷、對比、去重操做。

(六) 併發處理
1.**【強制】**獲取單例對象須要保證線程安全,其中的方法也要保證線程安全。

說明:資源驅動類、工具類、單例工廠類都須要注意。

2.**【強制】**建立線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。

正例:
public class TimerTaskThread extends Thread {
    public TimerTaskThread(){
        super.setName("TimerTaskThread");  ...
}
3.**【強制】**線程資源必須經過線程池提供,不容許在應用中自行顯式建立線程。

說明:使用線程池的好處是減小在建立和銷燬線程上所花的時間以及系統資源的開銷,解決資源不足的問題。若是不使用線程池,有可能形成系統建立大量同類線程而致使消耗完內存或者「過分切換」的問題。

4.**【強制】**線程池不容許使用Executors去建立,而是經過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。

說明:Executors返回的線程池對象的弊端以下:

1)FixedThreadPool和SingleThreadPool:

容許的請求隊列長度爲Integer.MAX_VALUE,可能會堆積大量的請求,從而致使OOM。

2)CachedThreadPool和ScheduledThreadPool:

容許的建立線程數量爲Integer.MAX_VALUE,可能會建立大量的線程,從而致使OOM。

5.**【強制】**SimpleDateFormat是線程不安全的類,通常不要定義爲static變量,若是定義爲static,必須加鎖,或者使用DateUtils工具類。

正例:注意線程安全,使用DateUtils。亦推薦以下處理:
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};
說明:若是是JDK8的應用,可使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替Simpledateformatter,
官方給出的解釋:simple beautiful strong immutable thread-safe。
6.**【強制】**高併發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。

7.**【強制】**對多個資源、數據庫表、對象同時加鎖時,須要保持一致的加鎖順序,不然可能會形成死鎖。

說明:線程一須要對錶A、B、C依次所有加鎖後才能夠進行更新操做,那麼線程二的加鎖順序也必須是A、B、C,不然可能出現死鎖。

8.**【強制】**併發修改同一記錄時,避免更新丟失,要麼在應用層加鎖,要麼在緩存加鎖,要麼在數據庫層使用樂觀鎖,使用version做爲更新依據。

說明:若是每次訪問衝突機率小於20%,推薦使用樂觀鎖,不然使用悲觀鎖。樂觀鎖的重試次數不得小於3次。

9.**【強制】**多線程並行處理定時任務時,Timer運行多個TimeTask時,只要其中之一沒有捕獲拋出的異常,其它任務便會自動終止運行,使用ScheduledExecutorService則沒有這個問題。

10.*【推薦】*使用CountDownLatch進行異步轉同步操做,每一個線程退出前必須調用countDown方法,線程執行代碼注意catch異常,確保countDown方法能夠執行,避免主線程沒法執行至countDown方法,直到超時才返回結果。

說明:注意,子線程拋出異常堆棧,不能在主線程try-catch到。

11.*【推薦】*避免Random實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed致使的性能降低。

說明:Random實例包括java.util.Random的實例或者 Math.random()實例。

正例:在JDK7以後,能夠直接使用API  ThreadLocalRandom,在 JDK7以前,能夠作到每一個線程一個實例。
12.*【推薦】*經過雙重檢查鎖(double-checked locking)(在併發場景)實現延遲初始化的優化問題隱患(可參考 The "Double-Checked Locking is Broken" Declaration),推薦問題解決方案中較爲簡單一種(適用於JDK5及以上版本),將目標屬性聲明爲 volatile型。

反例:
class Foo {
private Helper helper = null;
    public Helper getHelper() {
    if (helper == null)  synchronized(this) {
        if (helper == null)
            helper = new Helper();
        }
        return helper;
    }
    // other functions and members...
}
13.【參考】volatile解決多線程內存不可見問題。對於一寫多讀,是能夠解決變量同步問題,可是若是多寫,一樣沒法解決線程安全問題。若是是count++操做,使用以下類實現:AtomicInteger count = new AtomicInteger(); count.addAndGet(1);若是是JDK8,推薦使用LongAdder對象,比AtomicLong性能更好(減小樂觀鎖的重試次數)。

14.【參考】 HashMap在容量不夠進行resize時因爲高併發可能出現死鏈,致使CPU飆升,在開發過程當中注意規避此風險。

15.【參考】ThreadLocal沒法解決共享對象的更新問題,ThreadLocal對象建議使用static修飾。這個變量是針對一個線程內全部操做共有的,因此設置爲靜態變量,全部此類實例共享此靜態變量,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,全部此類的對象(只要是這個線程內定義的)均可以操控這個變量。
public enum WeekEnum {
    Monday(1,"週一"),
    Tuesday(2,"週二"),
    Wednesday(3,"週三");
    int idx;
    String description;
    WeekEnum(int idx, String description){
        this.idx = idx;
        this.description = description;
    }

}

WeekEnum mond = WeekEnum.Monday;
        switch(mond){
            case Monday:
                System.out.println("monday...");
                break;
            case Tuesday:
                System.out.println("Tuesday...");
                break;
            case Wednesday:
                System.out.println("Wednesday...");
                break;
                default:
                    System.out.println("others....");
                    break;
        }


Java編程語言(第三版)---Java四大名著----James Gosling(Java之父)

 Java編程思想(第4版)----Java四大名著----------------Bruce Eckel

JAVA 2核心技術 卷I:基礎知識(原書第8版)---Java四大名著-----Cay Horstmann

JAVA 2核心技術 卷II:高級特性(原書第8版)----Java四大名著-----Cay Horstmann

Effective Java中文版------Java四大名著--------Joshua Bloch

在線查看effectiv java

相關文章
相關標籤/搜索