2018年11月22日 星期四

eclipse 啟動失敗 出現java.lang.ArrayIndexOutOfBoundsException

用了eclipse 這麼久,第一次遇到這個問題 記錄一下

在前次關閉eclipse都很正常的情況下,在啟動eclipse 竟然出現一個警訊 說無法啟用,要我去看LOG 檔 ,在eclipse\configuration\ 下可以看到log file 出現了以下的錯誤訊息:

.....
!ENTRY org.eclipse.osgi 4 0 2018-11-22 09:47:13.010
!MESSAGE Application error
!STACK 1
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.util.Arrays.copyOfRange(Unknown Source)
at java.util.Arrays.copyOfRange(Unknown Source)
at org.eclipse.ui.internal.ide.ChooseWorkspaceDialog.lambda$7(ChooseWorkspaceDialog.java:380)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.collect(Unknown Source)
at org.eclipse.ui.internal.ide.ChooseWorkspaceDialog.createUniqueWorkspaceNameMap(ChooseWorkspaceDialog.java:382)
at org.eclipse.ui.internal.ide.ChooseWorkspaceDialog.createRecentWorkspacesComposite(ChooseWorkspaceDialog.java:325)
at org.eclipse.ui.internal.ide.ChooseWorkspaceDialog.createDialogArea(ChooseWorkspaceDialog.java:176)
at org.eclipse.jface.dialogs.TitleAreaDialog.createContents(TitleAreaDialog.java:158)
at org.eclipse.jface.window.Window.create(Window.java:426)
at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:1095)
at org.eclipse.jface.window.Window.open(Window.java:783)
at org.eclipse.ui.internal.ide.ChooseWorkspaceDialog.prompt(ChooseWorkspaceDialog.java:114)
at org.eclipse.ui.internal.ide.application.IDEApplication.promptForWorkspace(IDEApplication.java:342)
at org.eclipse.ui.internal.ide.application.IDEApplication.checkInstanceLocation(IDEApplication.java:261)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:128)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:388)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:243)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:673)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:610)
at org.eclipse.equinox.launcher.Main.run(Main.java:1519)



經上網查了一下,排除方式很容易,只要將eclipse/configuration/.settings中的所有文件刪除就可以正常開啟了,但刪除後,一些設定包含先前記下的workspace都會被重設,不過這比不能啟動來說,還算OK啦。

而有其它篇文章有寫到  刪除 eclipse/configuration/.settings/org.eclipse.ui.ide.prefs kot. 就可以,因我已先整個目錄都刪除了,沒機會實測,等下次再碰到時再確認看看。

參考資料:

2018年11月9日 星期五

JavaScript object 如何轉換成 JSON string


有時想要查看Json的內容,就直接output來看
但看到的結果就是object

這時就要用JSON.stringify() 轉換成 string
這個其實很常用,但常常忘了,就直接output
所以寫下來才不會浪費一些時間

作法如下:


var obj={"name":"binchen"};

console.log(obj);

console.log(JSON.stringify(obj));


產出會如下圖:
用console看是沒啥差,但用alert 

請點這裡看線上Demo

2018年11月6日 星期二

HttpClient 連結Https 出現javax.net.ssl.SSLHandshakeException 問題排除


最近在排除一個HTTPS API 連線的問題,當連線時會丟出以下錯誤

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
    at sun.security.ssl.AppOutputStream.write(Unknown Source)
    at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
    at java.io.BufferedOutputStream.flush(Unknown Source)
    at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:506)
    at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2114)
    at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1096)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)


這個在二三年前運行正常,看來應該是目前SSL各Server都修補SSLv3漏洞,目前都僅支援TLS,所以才變成不能使用
經查詢,蠻多人都有遇到此問題,大致問題點是無法進行憑證確認,找了很多方法其實都沒法排除,相關測過的如下,如想要看我的排除法,請直接看第4點即可:
1. 在JVM 啟動時加上  -Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1.0
首先,該異常發生的時機,是在Client與Server之間進行的Handshake的過程中,Client與Server之間的有效數據傳輸還沒有開始。
原因一:針對上述Handshake的過程,該異常往往發生在第4步,即Client得到服務器的數字證書時,向CA驗證證書有效性時。
Client在試圖向可信CA進行驗證時,發現Server引用的CA,沒有出現在Client的Trust Store中。
原因二:此外,該異常也可能是由於Client與Server所使用的SSL / TLS版本不一致服務器使用的TLS版本高,而Client支持的TLS版本低。
我試了之後沒反應 ,也有照著其它加上 -Djavax.net.debug=all  出來的錯誤訊息和該網友的差不多,但還是不能排除,有另一解法說更新JDK到1.8 但該系統沒全面測過,所以還是作罷。
參考資料:
2. 更新jar  檔
部分網友解釋:是因為JDK中的JCE的安全機制導致錯誤,要去oracle的官網下載對應的JCE包替換JDK中的JCE包。
jce所在地址:%JAVA_HOME%\ jre \ lib \ security裡的local_policy.jar,US_export_policy.jar
JDK7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
但是我更新後和該網友一樣沒有解決,而他排除的方式是在請求連接之前,加上
System.setProperty(“https.protocols”,“TLSv1.2,TLSv1.1,SSLv3”);
但我試了還是一樣不行
參考資料:
https://blog.csdn.net/gege87417376/article/details/77936507
3.匯入證書簽章
因為turst失敗,所以要將證書匯入到伺服器,先將Server的憑證取回,可利用IE 查看該網站的SSL ,再進行匯出轉匯入,該動作如下:
1.用IE打開需要連接的HTTPS網址,會彈出如下對話框:
2.單擊“查看證書”,在彈出的對話框中選擇“詳細信息”,然後再單擊“複製到文件”,根據提供的嚮導生成待訪問網頁的證書文件
3.嚮導第一步,歡迎界面,直接單擊“下一步”,
4.嚮導第二步,選擇導出的文件格式,默認,單擊“下一步”,
5.嚮導第三步,輸入導出的文件名,輸入後,單擊“下一步”,
6.嚮導第四步,單擊“完成”,完成嚮導
7.最後彈出一個對話框,顯示導出成功
8.用keytool的工具把剛才導出的證書倒入本地keystore.Keytool命令在<java主> \ BIN \下,打開命令行窗口,並到<java主> \ lib \ security中\目錄下,運行下面的命令:
keytool -import -noprompt -keystore cacerts -storepass changeit -alias yourEntry1 -file your.cer
其中參數別名後跟的值是當前證書在密鑰庫中的唯一標識符,但是大小寫不區分;參數文件後跟的是剛才通過IE導出的證書所在的路徑和文件名;如果你想刪除剛才導入到密鑰庫的證書,可以用命令:
keytool -delete -keystore cacerts -storepass changeit -alias yourEntry1
但照做後還是一樣無法排除 ><。
參考資料:
4.最後排除的方式,為採用  httpclient跳過https請求的驗證的方式,實做驗證的方式然後自己加入讓他避掉原本網站要求
我們使用的是httpclient,其版本如下:

<dependency>
  <groupId>commons-httpclient</groupId>
  <artifactId>commons-httpclient</artifactId>
  <version>3.1</version>
</dependency>

接 下來要實作2個class,第一個是MyX509TrustManager(這個方法直接實現X509TrustManager,X509TrustManager在javax.net.ssl.X509TrustManager裡面),這串可以都不用更換即可使用。
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {
    /* (non-Javadoc)
    * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String)
    */
    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {

    }
    /* (non-Javadoc)
     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String)
     */
    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {

    }
    /* (non-Javadoc)
     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
     */
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}
接下來實作MySecureProtocolSocketFactory ,這個我調整了getInstance("SSL"),原本他是採行SSL,但現行伺服端加密方法都因資安考量,只限TLSv1 以上的才可以trust,所以記得要改一下,不然是不能排除問題的,目前在網路上類似的參考案例都是 getInstance("SSL"),所以用了大多會無法排除,要特別注意。
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpClientError;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;

public class MySecureProtocolSocketFactory implements SecureProtocolSocketFactory {

    //這裡新增一個屬性,主要目的就是來獲取ssl跳過驗證
    private SSLContext sslContext = null;
    /**
     * Constructor for MySecureProtocolSocketFactory.
     */
    public MySecureProtocolSocketFactory() {
    }
    /**
     * 這個建立一個獲取SSLContext的方法,匯入MyX509TrustManager進行初始化
     * @return
     */
    private static SSLContext createEasySSLContext() {
        try {
            SSLContext context = SSLContext.getInstance("TLSv1");
            context.init(null, new TrustManager[] { new MyX509TrustManager() },
                    null);
            return context;
        } catch (Exception e) {
            throw new HttpClientError(e.toString());
        }
    }

    /**
     * 判斷獲取SSLContext
     * @return
     */
    private SSLContext getSSLContext() {
        if (this.sslContext == null) {
            this.sslContext = createEasySSLContext();
        }
        return this.sslContext;
    }
    //後面的方法基本上就是帶入相關引數就可以了
    /*
     * (non-Javadoc)
     *
     * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String,
     *      int, java.net.InetAddress, int)
     */
    public Socket createSocket(String host, int port, InetAddress clientHost,int clientPort) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port,clientHost, clientPort);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.commons.httpclient.protocol.ProtocolSocketFactory#createSocket(java.lang.String,
     *      int, java.net.InetAddress, int,
     *      org.apache.commons.httpclient.params.HttpConnectionParams)
     */
    public Socket createSocket(final String host, final int port,final InetAddress localAddress, final int localPort,
                               final HttpConnectionParams params) throws IOException,UnknownHostException, ConnectTimeoutException {
        if (params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }
        int timeout = params.getConnectionTimeout();
        if (timeout == 0) {
            return createSocket(host, port, localAddress, localPort);
        } else {
            return ControllerThreadSocketFactory.createSocket(this, host, port,localAddress, localPort, timeout);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
     */
    public Socket createSocket(String host, int port) throws IOException,UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }

    /*
     * (non-Javadoc)
     *
     * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
     */
    public Socket createSocket(Socket socket, String host, int port,boolean autoClose) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(socket, host,port, autoClose);
    }
}
最後,我們在使用前加上即可避掉驗證
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
/*
 * 利用HttpClient進行post請求的工具類
 */
public class HttpClientUtil {

    public static String doGet(String url) throws Exception {
        //宣告
        ProtocolSocketFactory fcty = new MySecureProtocolSocketFactory();
        //加入相關的https請求方式
        Protocol.registerProtocol("https", new Protocol("https", fcty, 443));
        //傳送請求即可
        org.apache.commons.httpclient.HttpClient httpclient = new org.apache.commons.httpclient.HttpClient();
        GetMethod httpget = new GetMethod(url);
        System.out.println("======url:" + url);
        try {
            httpclient.executeMethod(httpget);
            return httpget.getResponseBodyAsString();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new Exception(ex.getMessage());
        } finally {
            httpget.releaseConnection();
        }
    }

}
參考資料:

2018年7月22日 星期日

如何更換Eclipse 為暗色系的主題?

近幾年,工程師們都喜歡將開發編輯工具調整使用偏用暗色系當背景
多半是說這樣對眼睛比較好,而且在看程式碼時的辦識度,也比傳統白底的背景來的高

所以,當然不免俗也來更換一下暗色系背景,不過預設eclipse的幾個Theme並沒有暗色系的
因此,要改去其它地方下載安裝才行,不麻煩很容易,照著下面步驟執行即可

1. 請至 Eclipse Color Theme

 2.左方的Clone or download 點下按Download ZIP 下載這Theme套件

3. 解開ZIP後將eclipse-ui-themes-master 目錄移至 eclipse\dropins 下

4.重啟eclipse 
5.在eclipse 上方功能列 windows,點選選單 Preferences -> General -> Appearance -> Color Theme 即可設定 

6. 這樣就完成啦

當然選擇這種方式的安裝,你也可以透過 marketplace.eclipse.org 進行下載安裝,這個我就不介紹啦,有興趣的請自行連過去安裝 ^.^

2018年6月14日 星期四

Apache 阻擋 Slow HTTP Denial of Service Attack

最近又在進行客戶系統的弱點掃描,這次被掃到一個Medium Risk

Slow HTTP Denial of Service Attack

真是怪,每用一套不同的弱掃工具,就會掃到一些弱點

關於這個Slow DOS 攻擊弱點,經上網查了一下,可以直接從Apache 啟用mod_reqtimeout模組來排除此問題

mod_reqtimeout是Apache伺服器預設的模組之一,主要的功能在於限定要求(Request)封包傳遞的速率,避免要求連線因傳遞速率過慢而長時間占住網站伺服器的連線。
由於Slowris應用的技巧在於利用傳送要求標頭(Request Header)時間過久,藉此來占住網站伺服器的連線數,以致於網站伺服器無法服務正常的連線,以達到拒絕服務(DoS)的效果,因此mod_reqtimeout模組即是利用限定傳送要求標頭及要求內容時間的方式,來降低Slowris攻擊的危害。

可至 http.conf 啟用 mod_reqtimeout 把以下這行 # 去除

LoadModule reqtimeout_module modules/mod_reqtimeout.so

並再加上以下設定

<ifmodule mod_reqtimeout.c="">
  RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</ifmodule>


再重啟後重測,就可以過關了

當然還有其它方法排除,有興趣者就自已再去google 吧

2018年4月23日 星期一

mysql 記錄 執行過久的SQL

如mysql要查詢執行過久的SQL,可在參數檔my.ini or my.cnf 中的[mysqld]下方加上以下參數

slow_query_log = 1
slow_query_log_file = /var/logs/mysql_log/mysql_slow.log
long_query_time = 5   單位是s
log_queries_not_using_indexes = 1 這可以列出無使用index的SQL

如果要同時列出無使用index 的SQL,這樣LOG檔會有非常多SQL,所以建議這行不加或設定0,真的有需要再開啟

如果log檔放置的路徑非在mysql同層,那就要再設定目錄的權限,LOG才能正常被記錄在檔案之中,請依以下指令設定權限:


# mkdir   /var/logs/mysql_log
# chown mysql.mysql -R /var/logs/mysql_log

上述設定是mysql 5.6版之後的設定方式,之前的版本設定有些許不同,所以要先確認你的mysql版本喔

此外,long_query_time 在mysql 5.6版本之後,可以設定0.x秒 之前版本可都是要1秒以上

2018年4月18日 星期三

排除 error command line calculator 'bc' not found centos

在centos 執行 sh 時 出現了 error command line calculator 'bc' not found centos 錯誤訊息

查了一下才知才了 BC shell

執行安裝指令如下:

# yum -y install bc

安裝完成再重新執行該sh 就可正常運行了

CentOS Ntp Server 校對伺服器的建立


在 CentOS 7 陸續有許多新的工具出現,不單只是kernel的改變,包含一些我們慣用的工具都也汰換成新的,像校對時間的Server  也改成 chronyd ,但因為chronyd 預設開啟的Port 為323,並非原本的123 Port ,所以此篇要信紹一下原本及比較常用的NTPD service

因為預設校對時間的工具chronyd 會和ntp 搶
一整個怪,查過沒有搶Port,反正就是一山容不下二虎
所以要先關原服務,不然等會設定自動啟動時會失效


# systemctl stop chronyd.service
# systemctl disable chronyd.service


這裡要注意一下,我在測試時發現 加了service 竟然移不掉 最後是把service 字眼移除才能正常
所以執行上述動作後,可以先執行以下查詢自動啟用的service,看看是否chronyd有無移除成功
 systemctl list-unit-files | grep enabled


利用yum先進行安裝
# yum install ntp -y

設定要校時的NTP server
# vi /etc/ntp.conf

把原本的註解掉
#server 0.rhel.pool.ntp.org
#server 1.rhel.pool.ntp.org
#server 2.rhel.pool.ntp.org

並加上以下這幾台,如果是無法連外的區網,就要找區網內的校對伺服器
server tw.pool.ntp.org
server  watch.stdtime.gov.tw
server  time.stdtime.gov.tw

如果要設定 BIOS 的時間也同步調整,請修改 /etc/sysconfig/ntpd,

 # vi /etc/sysconfig/ntpd

並設定SYNC_HWCLOCK=yes 參數即可


啟動我們的NTP Server,並設定自動啟動及開啟防火牆
# systemctl enable ntpd
# systemctl start ntpd
# firewall-cmd --add-port=123/udp --permanent && systemctl restart firewalld

改時區可下指令
# timedatectl set-timezone Asia/Taipei

雖然也可以手動進行校時,指令如下:
# ntpdate pool.ntp.org

校時要先關掉本機的ntp服務,不然執行該指令會有錯誤訊息出現

最後可以使用 ntpstat 或 ntpq -p 指令檢查time server設定是否正確

[root@localhost]# ntpstat
synchronised to NTP server (118.163.81.61) at stratum 3
   time correct to within 68 ms

   polling server every 1024 s



注意: 在一啟動時就想查查看ntpstat 是否ntp有效果,但得到的都是unsynchronised,要等久一點才會同步成功,所以可以過一陣子再來看結果

2018年4月16日 星期一

排除 Can't locate Text/Template.pm in.CentOS

在CentOS 要執行perl ,出現了 Can't locate Text/Template.pm in. 一堆錯誤訊息

查了一下 少裝了  perl-CGI-Session 套件 所以立馬安裝

# yum install perl-CGI-Session -y

裝完後再重新執行,就能正常運行了

2018年4月13日 星期五

Centos 7 vsftpd 如何設定虛擬目錄

在設定vsftpd時,要指定虛擬目錄
原本使用了ln -s(Symbolic Link) 的方式來連結

雖然看起來可以,但透過FTP 連入時竟然是不可以用,會出現 550 Failed to change directory 的錯誤訊息

去Google查了一下, 因為chroot 不能使用 soft link 所以要改用mount bind的方式

可先建立你想要的目錄名稱
# mkdir /ftproot/upload

然後再下mount 指令
# mount --bind /source/upload /ftproot/upload

這樣就可以在FTP 連入 upload 目錄 看到/source/upload 目錄的檔案了
不過,重開機後就失效了,所以如果要讓設定一直生效就要在/etc/fstab 下加入mount指令

# vi /etc/fstab
在最後加上
/source/upload  /ftproot/upload/ none bind,ro 0 0


這樣重啟後,就可以直接mount上去啦

參考連結:

  • http://blog.ilc.edu.tw/blog/index.php?op=printView&articleId=470470&blogId=25793
  • https://unix.stackexchange.com/questions/413823/editing-etc-fstab-to-permanently-bind-mount-directory


2018年2月21日 星期三

java.net.URLEncoder.encode is deprecated 排除方式

太久沒有寫連線程式了

在做參數轉換時才知 java.net.URLEncoder.encode is deprecated
查了一下只要稍為轉換一下就可以了


主要是要進行編碼時,要指定編碼格式 EX:

URLEncoder.encode("{123, abc}","UTF-8");

這樣即可進行轉碼了

2018年2月14日 星期三

Java List 插入 刪除基本觀念

當我們要針對集合進行插入及刪除時,JAVA原生就已提供相關的方法可以使用

但往往在使用時,如果基本觀念不清楚,就會不小心留下一隻大肥蟲

例如 以下的Code:
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
System.out.println(list);

當直接 output 時會顯示 [A, B, C, D, E]
如果我們進行插入時,加入F,如下範例: 

list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add(2, "F");
System.out.println(list);

這時output 會顯示 [A, B, F, C, D, E ] 他會在此List 的index 位置2 插入F  
(只要是陣列 集合都是從0開始起算)

如果我們想要先進行刪除B,如下:

list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.reomve(1);
list.add(2, "F");
System.out.println(list);

這時output 會顯示 [A, C, F,  D, E ] ,由此可證 被刪除和插入,List index 都會即時做變化
因此,在進行List處理時,如果要直接使用index異動,就要注意會有此問題
或是我們可以改用 Iterator 即可避掉刪除的問題