2017年7月9日 星期日

PLSQL Developer 好用的設定

※顯示行號

SQL的行號



PL SQL 的行號




※编辑用快速鍵

指的是下 SQL 時的快速鍵,Tools-->Preferences


※此時可以用如下的設定
S=SELECT * FROM
W=WHERE
GB=GROUP BY
OB=ORDER BY

=前後不能空,要使用時,只要下S空格,就會出=後面的字了

※此檔當然不能刪除



※功能快速鍵


※用滑鼠按右邊想改的地方會反白,此時按想設定的快速鍵即可
以下是個參考,設定成與 Eclipse 一樣
Edit / Undo:Ctrl+Z
Edit / Redo:Ctrl+Y
Edit / PL/SQL Beautifier:Shift+Ctrl+F
Edit / Selection / Indent:Tab
Edit / Selection / Unindent:Shift+Tab
Edit / Selection / Uppercase:Shift+Ctrl+X
Edit / Selection / Lowercase:Shift+Ctrl+Y
Editor: Delete Line:Ctrl+D

註解和反註解:
Edit / Comment:Shift+Ctrl+C
Edit / Selection / Uncomment:
這是多行註解 (/**/),這個軟體必需要用滑鼠選完文字後,才有用,而且不能有兩個都是一樣的快速鍵



※執行一行 SQL



※大部分的人一行都是一句 SQL,一句是以「;」區分的

※假設在編輯區全部有三句 SQL,按下如上的快速鍵 (F8),每句都會執行

※但大部分的時候,想要執行的只是游標所在的那一行(一句),此時可以如下的設定


※此時只會執行游標當前,但二句(含)以上會出錯



2017年7月3日 星期一

參數預設值、次方、解構賦值

※參數預設值

window.onload = () => {
    let num = 2;
    multiply1(num);
    multiply2(num);
    multiply3(num);
}
    
function multiply1(a, b) {
    b = (typeof b !== 'undefined') ?  b : 1;
    alert(a * b);
}
    
function multiply2(a, b = 1) {
    alert(a * b);
}
    
function multiply3(a, b = xxx()) {
    alert(a * b);
}
    
let xxx = () => {
    return 1;
}

※原本是像 multiply1 的寫法,可以在參數上做手腳,就變成了 multiply2 的寫法

※multiply3 是呼叫 method 後得到回傳值,最後也是和 multiply2 一樣
如果想用匿名的方式寫在等於後面,要在最後加上「()」

※如果給 undefined 是 OK 的,但給 null,數字相當於給 0,字串相當於給 null 字串



※次方

console.log(2 ** 3 ** 2); // 512,寫法不好,易造成誤解,用下面的
console.log(2 ** (3 ** 2)); // 512
console.log((2 ** 3) ** 2); // 64
    
// console.log(-2 ** 3); // 負數會報錯,用下面的
console.log(-(2 ** 3)); // -8





※解構賦值


※[]


window.onload = () => {
    // 字串
    data = "123";
    let [a, b] = data;
    console.log(a, b); // 1 2
    
    let {length: len} = data;
    console.log(len); // 3
    
    // 陣列,多餘的元素用不到
    let [a,b] = [1,2,3,4];
    console.log(a); // 1
    console.log(b); // 2
    
    // 巢狀
    let x = [1, ["a", "b", "c"], 3, 4];
    let [c, d] = x
    console.log(d); // "a", "b", "c"
    
    let [, [,,f]] = x
    console.log(f); // c
    
    // 呼叫 function
    let [a1, , b1] = fx();
    console.log(a1); // 1
    console.log(b1); // 3
    
    function fx(){
        return [1,2,3,4];
    }
    
    // 剩下的為剩餘參數
    let [c,d,...rest] = [1, 2, 3, 4, 5];
    console.log(c); // 1
    console.log(d); // 2
    console.log(rest); // [3, 4, 5]
    
    // 預設值
    let [e=5, f=7] = [1];
    console.log(e); // 1
    console.log(f); // 7
    
    // 變數內容交換
    let g = 1;
    let h = 3;
    [g, h] = [h, g];
    console.log(g); // 3
    console.log(h); // 1
}





※{}

// 一般
let {p, q} = {p: 42, q: true};
console.log(p); // 42
console.log(q); // true 
// p 和 q 必需和 json 裡的 key 一樣
// 因為是使用名稱區分,所以位置調換不會影響結果
// 不能使用如 {,,p}
    
// 取代變數名稱
let {xxx: x, ooo: o} = {xxx:24, ooo:false};
// console.log(xxx); // 報錯,不可再使用原來的 xxx 變數
// console.log(ooo); // 報錯,不可再使用原來的 ooo 變數
console.log(x); // 24
console.log(o); // false
// 由於 xxx 和 ooo 有可能全域就定義過這個變數名稱了,這時會報錯,所以才有這個功能
    
// 巢狀 JSON
let {aaa, bbb: {k2: b}} = {bbb: {k2: 2}, aaa: {k1: 1}};
console.log(aaa); // {k1:1}
console.log(aaa.k1); // 1
console.log(b); // 2
    
// JSON 裡有陣列
let src = {data: {ccc: [1, 2, 3]}};
let {data: {ccc: [, , c]}} = src
console.log(c); // 3
    
// function
function fx({data: {ccc: [, , c]}}) {
    console.log(c); // 3
}
fx(src);
    
// 預設值
let {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5
    
// 迴圈
let data = [
    {
        xxx: "x",
        ooo: {
            a: 1,
            b: 2
        },
        zzz:'z'
    },
    {
        xxx: "xx",
        ooo: {
            a: 3,
            b: 4
        },
        zzz:'zz'
    }
];
    
for (let {xxx: s, zzz: d, ooo: {a:n} } of data) {
    console.log('xxx=' + s + ', d=' + d + ", ooo.a=" + n);
}
// xxx=x, d=z, ooo.a=1
// xxx=xx, d=zz, ooo.a=3





※()

window.onload = () => {
    ({a, b} = {a:1, b:2}); // 最前面不能加 let var const,{}開頭是一定要有 let var const 的
    console.log(a); // 1
    console.log(b); // 2
    
    ({a, b} = {c:1, d:2});
    console.log(a); // undefined
    console.log(b); // undefined
    // console.log(c); // 報錯
    // console.log(d); // 報錯
    
    ({a, b, ...rest} = {a:1, b:2, c:3, d:4});
    console.log(a, b, rest); // 1 2 {c:3, d:4}
}





2017年7月2日 星期日

集合的刪除

※List

List<Integer> list = new LinkedList<>();
list.add(4);
list.add(1);
list.add(3);
list.add(2);
    
// int x = list.size();
for (int i = 0; i < list.size(); ++i) {
    /*
    if (list.get(i) == 3 || list.get(i) == 1) {
        list.remove(i);
        i--;
    }
    */
    list.remove(i);
}
    
/*
Iterator<Integer> it = list.iterator(); 
while (it.hasNext()) {
    Integer i = it.next(); 
    if (i == 3) it.remove(); 
}
*/
    
/*
for (Iterator<Integer> it = list.iterator(); it.hasNext();) {
    Integer i = it.next();
    if (i == 3) it.remove();
}
*/
    
System.out.println("size=" + list.size());
System.out.println("list=" + list);

※此例並不會全移除,會發現還有兩個元素,因為移除後, index 會自動往上移
元素:index-->  4:0   1:1   3:2   2:3
迴圈跑一圈後會變成 1:0   3:1   2:2
迴圈跑兩圈後會變成 1:0   2:1,所以會剩下內容為 1 和 2
可以通過移除後,將迴圈裡的變數 i 減 1 達成,但用 Iterator 會比較漂亮,再或者用 for 加iterator 也可以

※remove 完後就 break 是可行的,但不適合有重覆的元素

※從元素最後開始遍例到最前面,也就是用 i-- 的方式可以解決 index 自動往上移的問題


※Java8 List

List<String> list = Stream.of("a", "b", "c", "c", "e").collect(Collectors.toList());
list.removeIf(data -> "c".equals(data) ? true : false); // data -> "c".equals(data) 
// 或 new String("c")::equals
/*
list.forEach(i -> {
    if ("c".equals(i)) {
        list.remove(i);
    }
});
*/
System.out.println(list);

※使用 forEach 然後 remove 是不行的

※Map

Map<String, Integer> map = new TreeMap<>();
map.put("four", 4);
map.put("one", 1);
map.put("three", 3);
map.put("two", 2);
    
Iterator<Entry<String, Integer>> it = map.entrySet().iterator();
while(it.hasNext()){
    Entry<String, Integer> i = it.next();
    if(i.getValue() == 3){
        it.remove();
    }
}
    
/*
for (Iterator<Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext();) {
    Entry<?, Integer> i = it.next();
    if (i.getValue() == 3) {
        it.remove();
    }
}
*/
    
System.out.println("size=" + map.size());
System.out.println("map=" + map);



※Java8 Map

List<String> list = Stream.of("a", "b", "c", "d", "e").collect(Collectors.toList());
Map<String, Object> map = list.stream().collect(Collectors.toMap(Function.identity(), v -> "c"));
map.values().removeIf(data -> "c".equals(data) ? true : false); // map.keySet()、map.entrySet() 也都有 removeIf
/*
map.forEach((k, v) -> {
    map.remove(k);
});
*/
System.out.println(map);

※和 Java8 List 一樣,使用 forEach 然後 remove 會死得很難看

※Properties

Properties prop = System.getProperties();
//prop.list(System.out);
System.out.println(prop.size());
    
    //錯誤寫法
//    for (Entry<Object, Object> entrySet : prop.entrySet()) {
//        prop.remove(entrySet.getKey());
//    }
//    System.out.println(prop.size());
    
    // 正確寫法1
//    Iterator<Entry<Object, Object>> it1 = prop.entrySet().iterator();
//    while(it1.hasNext()){
//        Entry<Object, Object> entry = it1.next();
//        //if("".equals(entry.getKey("xxx")) )
//        it1.remove();
//    }
//    System.out.println(prop.size());
    
    // 正確寫法2
for(Iterator<Entry<Object, Object>> it2 = prop.entrySet().iterator(); it2.hasNext();) {
    Entry<Object, Object> entry = it2.next();
    //if("".equals(entry.getKey("xxx")) )
    it2.remove();
}
System.out.println(prop.size());



※原碼分析

List<String> list = new ArrayList<>();
list.add("11");
list.add("22");
list.add("33");
list.add("44");
    
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String data = it.next();
    System.out.println(data);
    if ("44".equals(data)) {
        list.remove(data);
    }
}

※刪除倒數第二個時(33)時,不會報錯,其他都會報「java.util.ConcurrentModificationException」的錯
這個 Exception 表示執行緒在刪除時,不能更改裡面的結構,不是修改值,如增加刪除都會改到結構,但單執行緒不知道為什麼也是這樣的限制,這樣的機制叫 fail-fast
Iterator 的 remove 最後也會呼叫 java.util.ArrayList 的 remove,但因為也個地方用的是 native,看不到原碼怎麼寫的,使得增加和原來的 size 一樣,所以不會報錯

※如果 33 有很多個且第一個是倒數第二個會和前面一樣,只會刪倒數第二個
但若第一個不是倒數第二個也是拋上面的例外,使用 for 也是一樣的情形

※ArrayList 重要原代碼

※從 java8 複製的

public E remove(int index) {
    rangeCheck(index);
    
    modCount++;
    E oldValue = elementData(index);
    
    int numMoved = size - index - 1;
    if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null; // clear to let GC do its work
    
    return oldValue;
}
    
    
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
    
    
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    
    ensureExplicitCapacity(minCapacity);
}
    
    
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    
    // overflow-conscious code
    if (minCapacity - elementData.length > 0) grow(minCapacity);
}

※使用 add、remove 時,modCount 變數都會加 1;size 變數使用 add 方法時會加 1;remove 方法時會減1

※Itr 重要原代碼

※java.util.ArrayList 有四個內部類別,Itr、ListItr、SubList、ArrayListSpliterator

※list.iterator() 時,會使用裡面的方法

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;
    
    public boolean hasNext() {
        return cursor != size;
    }
    
    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();
   
        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

※刪除 11、22、44 時:執行到 next() 後,會呼叫 checkForComodification(),上個迴圈執行 remove 後,modCount 變數會加1;而 expectedModCount 都是原本的長度 4
5 != 4,所以報錯

※刪除倒數第二個 (33) 時:這時要注意 hasNext()
cursor    size    value
0            1        11
1            2        22
2            3        33
3            4        44
刪除 33 後,執行下一次迴圈來到 hasNext(),size 會被減 1,所以 3 != 3 為 false,結束迴圈,造成不出錯的假像

※hasNext(),刪除11、22、33、44 時的情形,cursor != size 表如下:
11:0 != 4  -->  1 != 3
22:0 != 4  -->  1 != 4  -->  2 != 3
33:0 != 4  -->  1 != 4  -->  2 != 4  -->  3 != 3
44:0 != 4  -->  1 != 4  --> 2 != 4  -->  3 != 4  --> 4 != 3
除了 倒數第二筆 (33) 以外,其他都會繼續執行,呼叫 next(),再呼叫 checkForComodification(),就出錯了

※Itr 的 remove() 因為有 expectedModCount = modCount,所以不會有問題


※以上在多線程的情況還是會錯,可以使用 new CopyOnWriteArrayList<>() 解決
它會複製一份到別的地方,然後在將指向移到這個地方,所以不會有問題
複製前和指向前,如果有人要讀這份資料,取到的是舊值;指向後,取得的是新值
因為是複製一份,所以資料量大時會變慢



※陣列轉 List


String[] str = new String[] { "aa", "bb" };
List<String> list = Arrays.asList(str);
    
str[0] = "cc";
list.forEach(System.out::println);

※更改了原來的 String 陣列居然會影響 List,使用 Arrays.asList 才會,用 List.of、Stream.of、System.arraycopy 都不會有這種情形

2017年7月1日 星期六

Call、Apply、Closure

※Call、Apply


※this

window.onload = () => {
    new xxx();
    ooo.o();
    xxx();
    xxx.call();
    xxx.apply();
    xxx.call(ooo);
    xxx.apply(ooo);
    xxx.bind(ooo)();
}
    
let ooo = {
    o:xxx
}
    
function xxx(){
    console.log(this);
}

※結果:


※使用 new 時,this 指的是 new 的物件
JSON 裡的變數指定一個 function,此時 this 指的是這個 function
直接呼叫時,this == window
call 和 apply 沒有參數時,this == window;有參數時,this 指的是傳進去的參數

※最後的 bind 也很類似,但不會馬上執行,所以為了馬上執行,我在最後面加上「()」



※暫時變數

window.onload = () => {
    let o = new Obj(1,2);
    o.fun = plus;
    console.log(o.fun(o.x, o.y));
    delete o.fun;
    
    // console.log(plus.call(o, o.x, o.y));
    // console.log(plus.apply(o, [o.x, o.y]));
    
    // 這樣也可以
    // console.log(plus.call(Obj, 1, 2));
    // console.log(plus.apply(Obj, [1, 2]));
}
    
function plus(p1, p2){
    return p1 + p2;
}
    
function Obj (x, y) {
    this.x = x;
    this.y = y;
    return x * y;
}

※原本的作法比較麻煩,直接使用 call 或 apply ,就不用宣告暫時變數

※call 和 apply 第一個都是放物件,而 call 將要傳進去的參數一個一個放在後面;而 apply 只有二個參數,最後放陣列



※this

window.xxx = 'x';
window.onload = () => {
    window.xxx = 'xx';
    let obj = {xxx:'xxx'};
    
    showXxx.call(window); // xx
    showXxx.call(this); // xx
    showXxx.call(obj); // xxx
    
    showXxx.apply(window); // xx
    showXxx.apply(this); // xx
    showXxx.apply(obj); // xxx
}
    
function showXxx(){
    alert(this.xxx);
}

※要注意如果 onload 裡沒有 window.xxx,會抓更外面的


※還可參考高手寫的文章

※Closure

內層可以呼叫外層的變數,但外層不能呼叫內層的變數,但可以利用閉包來達到類似的功能

let name = 'outside 2';
window.onload = () => {
    let name = 'outside';
    let o = {
        name : 'inside',
        getName:function(){
            // return this.name; // inside
            return function(){
                // return xxx();
                return this.name;
            }
        }
    };
    alert(o.getName()()); // outside
}
    
function xxx(){
    return this.name;
}

※閉包首先要了解變數存活在哪



※累加

let name = 'outside';
function xxx(x) {
    let name = x;
    return function(x){
        name += x;
        return name;
    }
}
    
let o = xxx(5);
alert(o(1)); // 6
alert(o(2)); // 8
alert(o(3)); // 11

※還可以參考高手寫的