文章加密

;

2020年12月5日 星期六

Java Udemy 學習筆記3--functional programming:

  • functional programming:  they are first class citizen(就是個歷史稱呼)
    compare to structure programming(just like for loop), functional programming have two points:
    1. don't have mutation variable
    2. tell what to do, not how to do
  • cheesy: adj 俗氣的
  • lambda expression:  匿名函式

In Java, what are the advantages of streams over loops? [closed]


Interesting that the interview question asks about the advantages, without asking about disadvantages, for there are are both.

Streams are a more declarative style. Or a more expressive style. It may be considered better to declare your intent in code, than to describe how it's done:

 return people
     .filter( p -> p.age() < 19)
     .collect(toList());

... says quite clearly that you're filtering matching elements from a list, whereas:

 List<Person> filtered = new ArrayList<>();
 for(Person p : people) {
     if(p.age() < 19) {
         filtered.add(p);
     }
 }
 return filtered;

Says "I'm doing a loop". The purpose of the loop is buried deeper in the logic.

Streams are often terser. The same example shows this. Terser isn't always better, but if you can be terse and expressive at the same time, so much the better.

Streams have a strong affinity with functions. Java 8 introduces lambdas and functional interfaces, which opens a whole toybox of powerful techniques. Streams provide the most convenient and natural way to apply functions to sequences of objects.

Streams encourage less mutability. This is sort of related to the functional programming aspect -- the kind of programs you write using streams tend to be the kind of programs where you don't modify objects.

Streams encourage looser coupling. Your stream-handling code doesn't need to know the source of the stream, or its eventual terminating method.

Streams can succinctly express quite sophisticated behaviour. For example:

 stream.filter(myfilter).findFirst();

Might look at first glance as if it filters the whole stream, then returns the first element. But in fact findFirst() drives the whole operation, so it efficiently stops after finding one item.

Streams provide scope for future efficiency gains. Some people have benchmarked and found that single-threaded streams from in-memory Lists or arrays can be slower than the equivalent loop. This is plausible because there are more objects and overheads in play.

But streams scale. As well as Java's built-in support for parallel stream operations, there are a few libraries for distributed map-reduce using Streams as the API, because the model fits.

Disadvantages?

Performance: A for loop through an array is extremely lightweight both in terms of heap and CPU usage. If raw speed and memory thriftiness is a priority, using a stream is worse.

Familiarity.The world is full of experienced procedural programmers, from many language backgrounds, for whom loops are familiar and streams are novel. In some environments, you want to write code that's familiar to that kind of person.

Cognitive overhead. Because of its declarative nature, and increased abstraction from what's happening underneath, you may need to build a new mental model of how code relates to execution. Actually you only need to do this when things go wrong, or if you need to deeply analyse performance or subtle bugs. When it "just works", it just works.

Debuggers are improving, but even now, when you're stepping through stream code in a debugger, it can be harder work than the equivalent loop, because a simple loop is very close to the variables and code locations that a traditional debugger works with.


  • The operations which return another stream as a result are called intermediate operations and the operations which return non-stream values like primitive or object or collection or return nothing are called terminal operations.
  • functional interface: Predicate, Consumer, Function
  • predicate: verb 斷言,結果true or false
  • Method reference: 可以用在static method 和instance method
  • multiThreading 讓CPU知道同時去執行程式
  • parallelism: noun 並行性
  • utilization: 使用率
  • 有兩種方法可以做多執行續:
    1. extends Thread class

        (1) 在override run裡寫上要這個執行續執行的內容
        (2) 在呼叫這個class執行時必須用start方法,而非run方法

    2. implements Runnable interface
  • 執行續有幾種狀態:
    1. new: 準備好了,但還沒start()
    2. runnable: start()了,但別的thread正在執行
    3. running: 正在執行
    4. blocked/ waiting: 等待外部服務給予response或database回應太慢或等待其他thread的資料
    5. terminated/ dead: thread中的程式全部執行結束
  • setPriority() // 有1最小,5是default,10最大。須注意priority只是個請求,不見得真的會這樣執行,一個設最小,一個設最大,這樣去執行也大概只有50%的機率他真的符合。感覺就是沒用阿~
  • .join()  // waits for the thread to die
  • miscellaneous: adj 繁雜的
  • yield: verb 讓步,讓位
  • Thread有兩個static method:
    1. Thread.sleep(milisecond);
    2. Thread.yield(); // 讓出CPU,但這只是個請求,不見得會這樣執行。
  • synchronized method 一次只能有一個thread在裡面執行。其他想執行的thread必須waiting。在Collection相關的class裡有許多方法是synchronized的,所以為了不讓thread有問題,出現了cocurrent Collections。
  • executor service
    ExecutorService executorService = Executors.newSingleThreadExecutor(); //一次只會執行一個thread
    executorService.execute(new Task1());
    executorService.execute(new Thread(new Task2()));


    ExecutorService executorService = Executors.newFixedThreadPool(2); // 限制一次可以執行的Thread數量
    executorService.execute(new Task1());

    executorService.execute(new Thread(new Task2()));

    executorService.shutdown();  //最後要記得加上,否則會一直開著
  • callable:adj 可召回的
  • 如果多執行續想要有回傳值,需用implements Callable的class

class CallableTask implements Callable<String> {

String name;

CallableTask(String str) {
this.name = str;
}

@Override
public String call() throws Exception {
// TODO Auto-generated method stub
Thread.sleep(1000);
return "Hello " + name;
}

}

public class CallableRunner {

public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<String> welcomeFuture = executorService.submit(new CallableTask("David"));
// Future is not really a result, it's a promise that there will be a result. So
// after that, we need to use get()
System.out.println("new completed");
String welcomeMsg = welcomeFuture.get(); // Once we call a get() method on the Future, then this would wait for the task to complete execution.
System.out.println(welcomeMsg);
System.out.println("main down");
executorService.shutdown();
}

}
  • exception handling
  • gobble up: verb ph 吞噬
  • Stack Trace: error且沒有ExceptionHandling 時,error msg從第二行開始會說明error來自哪一行,最上面是發生error的那一行,往下是觸發那一行的程式,...

        如果不處理error,在error之後的程式將不會執行。12行發現錯誤,且他沒有辦法處理,則回傳給6行,6行也不會處理,而他又是main,所以終止於error。

        處理了exception handling,在throw error以下的程式也不會執行!
  • flowery: adj 華而不時的 (文字或話語)、文謅謅的
                try {
String a = null;
a.length();
System.out.println("method1 end");
} catch (Exception e) {  // Exception是一個class
e.printStackTrace();  // 如果這邊不做處理,那就是直接吞掉錯誤訊息
} finally {  
                    System.out.println("Here always excecutes");
                }


try {
String str = "456";
str.toString();
return;  // 造成just before close scanner印不出來
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("close");
}
System.out.println("just before close scanner");

結果印出close 而已,不論有沒有error,有沒有return,finally一定會執行

  • finally不執行的狀況只有:
    1. 在finally中的程式出現error
    2. JVM crashes:
       
    System.exit(1);會造成,但別試,會造成entire application terminate,電腦會壞掉!
  • fishy:adj 可疑的
  • dicey: adj 有風險的,不確定的
  • Exception Hierarchy
    1. class Error extends Throwable {} 
        //  Error是開發者無法處理的錯誤,You can prevent but not handle them
        //  例如: JVM is out of memory, or think about a stack overflow error.
        //  要注意不要create這個Error才對
    2. class Exception extends Throwable {}  
        //  Exception才是開發者可以處理的錯誤,所以這才是開發者要注意的錯誤
  • recursion: noun 遞規
  • Exception有兩種:
    1. class InterruptedException extends Exception {}
        //  checked exceptions,表示risky, 任何出checked exception的都要處理它
    2. class RuntimeException extends Exception {}
        //  unchecked exceptions,這個不是很risky
        //  class NullPointerException extends RuntimeException{}
  • I'll put it on the back burner. (尤指因不緊急或不重要而)暫時擱置一旁
  • Whenever you throw checked exception, your method need to tell that in its signature(即需要宣告這個method會throw err). Or get error msg "Unhandled exception type Exception"
  • Exception本身也屬於checked exceptions 因為它有包含到~
  • cumbersome: adj 累贅的、低效的
try{
}catch( IOException | SQLException e ){ // can define multiple exceptions in a block
e.printStackTrace();
}

  • Never hide Exceptions
  • Do not use it for flow control, like redirect traffic, if...else
  • Spring framework makes most of the exceptions as RuntimeExceptions, so who use method don't need to consider exception!
  • Having global exception handling.
  • Make sure that in main method, you are not throwing exception to the outside world.
  • cakewalk:noun 輕而易舉的事
  • counter is not atomic
  • Atomic是指不能分割成若干部分的意思
  • concurrency:並發
  • lock:
https://www.cnblogs.com/dolphin0520/p/3923167.html  ↓

我们了解到如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

  1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

  2)线程执行发生异常,此时JVM会让线程自动释放锁。

  那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。

  因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。

  再举个例子:当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。

  但是采用synchronized关键字来实现同步的话,就会导致一个问题:

  如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。

  因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。


  • ConcurrentHashMap is Concurrent Collection.
  • Concurrent Collection offer thread-safety without significant performance impact in specific scenarios.
  • algorithm: noun 演算法
  • CopyOnWrite 每次的修改都會複製一個新的出來,非常耗能,但thread-safety,建議用在read very much, but modify very few。他只在修改的方法上用synchronized,get方法沒有,而因為修改都會建新的,所以thread-safety
  • java.lang import by default
  • allocate: verb 分配
  • takeaway:noun 主要資訊
  • 當override equals()也要override hashCode() // 這個不懂為什麼要
  • access modifiers: 

    關於class:
    1. private: 不可以用在class
    2. public: 在自己的和別的package裡都可以new它
    3. (default) 就是什麼都不加: 在自己的package裡都可以new它
    4. protected: 不可以用在class

    關於method和variable(兩者是一樣的觀念):
    1. private: 只能在同個class使用
    2. public: 在不同個package,也可以使用public method
    3. (default) 在同個package下都可用
    4. protected: 在同個package or subclass下都可用

    enforce Encapsulation
  • non-access modifier

    關於class:
    5. final: 不能再被extend. Like wrapper class

    關於method和variable(兩者是一樣的觀念):
    5. final: 
           method: 不能再被override
           variable: 只能設定初始值
           argument: 不能重設初始值,其實好的編程本來就不會去重設argument啦(不論有沒有加final)
       到底什麼時候用final呢?實際上推薦所有的method and variables都用,這就是所謂immutable programming,這讓code容易被理解。當然實際上不可能所有的都是final,但我們會試圖達到這樣的編程。
    6. static:
          讓method 可以直接被className呼叫,但須注意在static method裡不可以調用非static variable or method。例子有List.of() , Collections.sort()。
          讓variable shared across all instances!
  • public static final int CONSTANTNAME = value; // 這是個清楚設定constant value的寫法

  • privilege: noun 特權
  • nomenclature: noun 命名法
  • Enumeration: Enum, 它可以有variable, constructor, method
    Enum name可以做為variable 的type
    ordinal() :即index
先去買個書,之類的了解下,再決定一下要看什麼學習

沒有留言:

張貼留言