kyle shanks
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: 'Java Lambda 表達式、方法引用' disqus: kyleAlien --- Java Lambda 表達式、方法引用 === ## Overview of Content 如有引用參考請詳註出處,感謝 :smile: > **把行為包裝程物件**,也就是匿名類別,JDK 1.8 後引入 :::success * 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/) 本篇文章對應的是 [**認識 Java 函數式編程:從 Lambda 表達式到方法引用 | 3 種方法引用**](https://devtechascendancy.com/java-functional-lambda-methods/) ::: [TOC] ## 函數式編程 在軟體設計中物件導向範式(面向對象)就是將「數據」進行抽象,使數據擁有個人身份;而軟體設計中的 **函數式編程(`Functional Programming`)則是對 「==行為==」 進行抽象**,這個行為也就是函數,它會將 **函數視為參數** 來使用(以 C 語言來講可以想成是傳遞函數指標) ### 閉包 Closure 概念:與 Callback 的差別 > Java Lambda 就是閉包(`Closure`) * 在函數式編程中的其中一個重點就是「**閉包**, `Closure`」: 我們將這兩個中文字分開來看… 在數學中,所謂的「包」,只函數與周圍的環境變數綑綁打包;而「閉」則是指這些變數是封閉的,不會與外界有關係,只為該函數服務 > 運用在函數式編程中,閉包在解決問題時就會使用「**不可變的值**」 :::warning * **那 `Closure` 與 `Callback` 又有什麼不同**? > `Closure` 和 `Callback` 是程式設計中經常使用的概念,雖然它們在功能上有些相似,但在語義和應用上有所不同 * `Closure` 的特點在於「**環境的綁定**」,它可以捕捉並保存所屬環境中的變數,即使在閉包中已經超出了作用域 * `Callback`(回呼)是一個函數,它作為參數傳遞給另一個函數,並在某個時間點調用(通常是在某個操作完成後),並且「**不需要捕捉外部變數**」 > 回呼函數(`Callback`)允許非同步操作和事件驅動編程 ::: ### 為何要學函數式編程:與物件導向的差異 * **為何要學函數式編程**,它有什麼好處嗎? * 函數式編程是學習大數據的基礎 * 經過編譯器優化後,函數式編程通常可以取得更好的效率 編譯階段,Lambda 表達式會被轉換為與目標類型相容的實例;編譯器會產生一個私有的、靜態的、合成的「方法」,並透過 `invokedynamic` 指令來呼叫該方法 這種實作方式使得 Lambda 表達式的執行更加高效,因為它減少了物件的建立和方法呼叫的開銷 * 可以很好的運用在併發執行,並且這種運行是安全的 因為它在記憶體中使用的是「執行序私有空間 - 棧」,所以可以很好的避免高並發時的同步問題! * 減少匿名類的使用,減低開銷 * **類別載入開銷**:每次使用匿名內部類別時,都會產生一個新的類別,這增加了類別載入的開銷 * **物件建立開銷**:每次使用匿名內部類別時,都會建立一個新的對象,這增加了物件建立的開銷 * **與物件導向的差異**: 物件導向轉為函數編程有思想上的差距,我們可以透過下表來大致理解一下物件導向、函數式編程兩者個差異 | 範式 | 經典語言 | 核心概念 | 執行機制 | 突破點 | 實作原理 | 目的 | 常見應用 | | - | - | - | - | - | - | - | - | | 函數式 | Scheme/Haskell | 函數 | 計算運算式 | 突破機械思維的限制 | 引入高階函數,將「函數作為資料處理」 | 模擬數學思維,簡化程式、減少副作用 | 微積分計算、數學邏輯 | | 物件式 | Kotlin/Java | 物件 | 物件之間的資料交換 | 突破資料、程式碼分離的限制(強化資料的含義) | 引入封裝、繼承、多型機制 | 迎合人類的認知模式、提高軟體的易用重用性 | 大型複雜「互動式」系統 | ## Java Lambda :::info * **Java 的 Lambda 編成是在 JDK 1.8 後引入**,如果 Android 開發要使用記得要在 gradle 設定 `compileOptions` ```groovy= // Android gradle 中新增 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } ``` ::: ### 匿名類、Lambda 差異 * Java Lambda 是一個「**匿名**」函數,就是沒有函數名稱,而與其有個很相像的就是「**匿名類**」,以下以 以 RxJava 的 Subject 類來舉例看看兩者個差異(使用匿名類與 Lambda 都可以達到相同的功能) 1. **匿名類**:以下的 `Consumer` 就是界面,而我們創建的 `new Consumer` 就是匿名類 > ![image](https://hackmd.io/_uploads/BkIotUBuC.png) ```java= // 這是匿名類 AsyncSubject.create().subscribe( new Consumer<String>() { @Override public void accept(String s) throws Throwable { System.out.println("AsyncSubject: " + s); } }, new Consumer<Throwable>() { @Override public void accept(Throwable s) throws Throwable { System.out.println("AsyncSubject Error: " + s.toString()); } }, new Action() { @Override public void run() throws Throwable { System.out.println("AsyncSubject Complete"); } } ); ``` 2. **Lambda 表達**: 同樣的目的,但是以下使用 Lambda 的表達比起匿名類更加的精簡(可以用來簡化程式),而它又稱為「**匿名函數**」 ```java= // Lambda 表達 AsyncSubject.create().subscribe( s -> System.out.println("AsyncSubject: " + s), s -> System.out.println("AsyncSubject Error: " + s.toString()), () -> System.out.println("AsyncSubject Complete") ); ``` * 如果沒皆有處過 RxJava 框架的話,這邊舉另外個例子 我們可以以 Java 原生提供的 Thread 類為例,Thread 建構函數會接收一個 `Runnable` 界面,同樣使用「匿名類」、「匿名函數, `Lambda`」看看兩者的表面差異 > ![image](https://hackmd.io/_uploads/Sy09cISd0.png) 1. **使用匿名類表達 `Runnable` 界面** ```java= // Thread's Runnable 匿名類 new Thread(new Runnable() { @Override public void run() { System.out.println("Hello World"); } }); ``` 2. **使用 Lambda 表達**:可以看到這樣表達起來更加的簡潔 ```java= // Lambda 表達 new Thread(() -> System.out.println("Hello World")); ``` :::warning * 雖說「簡潔」,但是 Lambda 表達式是否合適每個人、團隊呢?這要取決於團隊成員的認可,只要團隊有共同認知即可,不一定用 Lambda 就是最佳的解 ::: ### Java Lambda 語法、格式 * 在 Java 程式中要使用 Lambda 表達式,需要使用 Java 引入的一個新語法(符號) ==`->`==: 符號 ==`->`== 以左是 Lambda 所需要的參數,以右是要處理的功能 (**當 Func 被呼叫時會執行的代碼**) ```java= // 左側 -> 右側 // 參數* -> 功能 (參數*) -> { // Lambda body System.out.println("Runnable lambda"); }; ``` :::info * 每種不同的程式語言在使用 Lambda 表達式時會有不同的表達方式(eg. 像是 swift 就是使用 `in` 關鍵字) * 如果 Lambda 表達式 Body 只有一行的話,則可以省略最外層的大括號 ```java= (參數*) -> System.out.println("Runnable lambda"); ``` ::: * 以下是一些常用的 Lambda 表達式(匿名函數),我們分為參數與返回值兩個特性對 Lambda 的表達差異來說明 * **參數數量對 Lambda 表達式的影響** 1. **無參數 Lambda 表達式** ```java= void noParamLambda() { Runnable runnable = () -> { System.out.println("Runnable lambda"); }; // 同上(由於 Lambda body 只有一行,所以可以省略大括號) Runnable runnable = () -> System.out.println("Runnable lambda"); } ``` 2. **一個參數的 Lambda 表達式**:如果只有一個參數,那也可以省略小括號 `()` ```java= void oneParamLambda() { Consumer<String> consumer = (msg) -> System.out.println("Consumer lambda: " + msg); Consumer<String> consumer2 = msg -> System.out.println("Consumer2 lambda: " + msg); Consumer<String> consumer3 = (String msg) -> System.out.println("Consumer lambda: " + msg); } ``` 3. **兩個或以上參數的 Lambda 表達式**:不能省略小括號,並且參數放置在小括號內 ```java= void twoParamsLambda() { IntConvert intConvert = (value1, value2) -> System.out.println("Consumer lambda: " + (value1 + value2)); } ``` * **返回值對 Lambda 表達式的影響**:Lambda 表達式如同一般的函數,返回值只能有一個 1. 使用 `return` 關鍵字 ```java= void lambdaWithReturn() { Comparable<Integer> comparable = value -> { int result = 0; if( value > 10) { result = 1; } return result; }; } ``` 2. 不使用 `return` 關鍵字: 另外 Lambda 表達式返回值有個特點,如果 Lambda 表達式中有返回值,並且我們也可以將 Lambda 表達式控制在「一行」中表達,那就可以省略 `return` 關鍵字 ```java= void lambdaWithReturnSingleLine() { // 由於 Body 只有一行,所以可以省略 return Comparable<Integer> comparable = value -> (value > 10 ? 1 : 0); } ``` ## 函數式介面 在前面的小節中,我們可以看到匿名類與匿名函數(Lambda)其實差異不大,那我們是否可以在 Java 中建立一個介面,並規定該介面可以轉為匿名函數呢? 答案是可以的~ 在這章中我們就來介紹 > ![image](https://hackmd.io/_uploads/By2SaQIuC.png) ### 自訂函數式介面:FunctionalInterface * 自訂函數式介面需要透過 `@FunctionalInterface` 這個註釋,該註釋保留到運行期間(`Runtime`);而使用這個註釋有幾個條件必須遵循,否則會出錯 1. 該註解只能註解在介面(`interface`)上 > ![image](https://hackmd.io/_uploads/H15ORXIuR.png) 2. 介面中 ==只有一個**抽象**方法== (但**可以使用 default、static 定義**),稱為函數式介面 > ![image](https://hackmd.io/_uploads/H1FbkN8_0.png) * 使用 **註釋**`@FunctionalInterface` 修飾的範例如下 1. 沒有用註釋修飾,編譯器並不會檢查 (Source),並且擁有一個以上的方法即不是函數式編程,無法取得函數式編程的好處、優點 2. 透過註釋修飾,檢查正確 (一個抽象介面),也可正常轉 Lambda 表達式 3. 雖然通過註釋修飾,但是超過一個以上的方法,無法編譯過 ```java= public class TestLambda { public static void main(String []args) { NonSymbol n = new NonSymbol() { @Override public void Print(String s) { System.out.println("Non Symbol"); } @Override public void Print(String s, String s2) { } }; HaveSymbol h = s -> System.out.println("Have Symbol"); } } // "1. " Okay, but not lambda interface NonSymbol { void Print(String s); void Print(String s, String s2); } // "2. " Okay @FunctionalInterface interface HaveSymbol { void Print(String s); default void Print(String s, String s2) { System.out.println(s + s2); } static void Print () { System.out.println("Static"); } } // "3. " Error @FunctionalInterface interface HaveTwoMethid { void Print(String s); void Print(String s, String s2); } ``` ### Java 內置函數式介面 * 除了自定義函數式介面之外,Java 也有提供給我們常使用的邏輯判斷介面,說明、範例如下表所示 | 函數式介面 | 參數 | 返回類 | Example | | ------------------------ | ------- | ------- | ------------------------- | | `Predicate<T>`(斷定) | `<T>` | boolean | 鄉民有 30 cm? | | `Consumer<T>`(消費) | `<T>` | void | Print Something | | `Function<T, R>`(功能) | `<T>` | `<R>` | 接收參數 T 加上 10 後返回 | | `Supplier<T>`(供應) | Non | `<T>` | 創建工廠,直接返回 | | `UnaryOperator<T>`(特殊 Function) | `<T>` | `<T>` | 單個操作數產生的運算結果 | | `BinaryOperator<T>`(特殊 Function) | `<T, T>` | `<T>` | 兩數的相加 | * [**Predicate 介面**](https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html) 可以用來做簡單的判定 範例如下:鄉民有 30 cm 的判斷 ```java= public class TestJavaAPI { public static void main(String []args) { boolean result = TestPredicate(31, // 傳入 Lambda 表達式 integer -> integer >= 30); System.out.println("鄉民有 30cm ? " + result); } private static <T> boolean TestPredicate(T value, Predicate<T> predicate) { return predicate.test(value); } } ``` > ![](https://i.imgur.com/AyUKESk.png) * [**Consumer 消費者介面**](https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html):該介面用於消費數據,當呼叫這個介面時就必須傳入相對的數值 範例如下:將傳入的數值,乘以三倍並打印出來 ```java= public class TestJavaAPI { public static void main(String []args) { TestConsumer(30, // 傳入 Lambda 表達式 (t) -> System.out.println("Value * 3 = " + t * 3)); } private static <T extends Integer> void TestConsumer(T value, Consumer<T> consumer) { consumer.accept(value); } ``` > ![](https://i.imgur.com/hnesbFI.png) * [**Function 介面**](https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html):該介面可以用來接收一個數據,並將其轉換為另外一種數據(可以把它記成一種轉換器) 範例如下:傳入一個字符串返回其長度 ```java= public class TestJavaAPI { public static void main(String []args) { int length = TestFunction("Alien_Pan", s -> s.length()); System.out.println("Test String Len: " + length); } public static <T extends String , U extends Integer> U TestFunction (T value, Function<T, U> function) { return function.apply(value); } } ``` > ![](https://i.imgur.com/5hovR4d.png) * [**Supplier 提供者介面**](https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html) :該介面可以用來作為「提供者」的角色 範例如下:創建小明個人資料,姓名、身高、體重 ```java= class MyInfo { String name; int height, weight; MyInfo(String name, int height, int weight) { this.name = name; this.height = height; this.weight = weight; } } @RequiresApi(api = Build.VERSION_CODES.N) public class TestJavaAPI { public static void main(String []args) { /* 原型 TestSupplier(new Supplier<MyInfo>() { @Override public MyInfo get() { return null; } }); */ MyInfo info = TestSupplier(() -> new MyInfo("Alien", 170, 65)); System.out.println("Name: " + info.name); System.out.println("Height: " + info.height); System.out.println("Weight: " + info.weight); } public static <T> T TestSupplier(Supplier<T> supplier) { return supplier.get(); } ``` > ![](https://i.imgur.com/9zoJwr7.png) ## 方法引用 方法引用(`Method References`)算是 Lambda 表達式函數的一部份 方法引用是一種簡潔且易讀的語法,允許我們「**直接引用現有的方法、建構函數、數組**」,而 **不需要明確地編寫 Lambda 表達式** > 它在本質上是 Lambda 表達式的一種簡化形式,提供了一種更簡潔的方式來表示某些常見的 Lambda 表達式 ### 方法引用 Method References * 在 Java 中方法引用時,需要配合 `::` 操作符,它將方法名和物件、類的名稱分開… 常見的使用方式如下 1. 物件`::`建構函數 2. 類`::`靜態方法 3. 類`::`實例方法 :::warning 使用方法引用時我們可以忽略參數的傳入,而這個前提條件則是:**必須與方法引用的參數列表 ==保持一致== 才可忽略** ::: * 當使用 Lambda 表達式時,會去實現抽象介面,但如果該介面 **已被實現** 則可以直接引用,範例如下: ```java= public static void main(String []args) { // 1. static 方法 //Consumer<String> consumer = s -> System.out.println(s); 原型 Consumer<String> consumer = System.out::println; // 2. 與引用方法的參數列表不一致,所以不能使用方法引用 Consumer<String> consumer_1 = s -> System.out.println("Name: " + s); // 3. 並無修改參數,可使用引用 static BinaryOperator<Integer> b = Math::max; // 4. 類普通方法的引用 String s = TestUnaryOperator("Alien", String::toUpperCase); System.out.println(s); } public static String TestUnaryOperator(String str, UnaryOperator<String> unaryOperator) { return unaryOperator.apply(str); } ``` ### 建構函數引用 Constructor Reference * 建構函式(也稱為建構器)也可以使用方法來引用 其引用的格式為 `ClassName::new`… 只要函數介面與建構器的參數列表匹配,就可以自動與介面中的方法相容(即與介面中的參數列表相吻合);以下是一個範例 ```java= class MyInfo { String name; int height, weight; MyInfo() { } MyInfo(String name, int height, int weight) { this.name = name; this.height = height; this.weight = weight; } } public static void TestMethod_2() { //"1. " 參數列表不吻合,Supplier 是一個無參介面 Supplier<MyInfo> s1 = () -> new MyInfo("Alien", 100, 35); //"2. " 使用無參構造器與無參介面吻合,可以使用建構函數引用 Supplier<MyInfo> s2 = () -> new MyInfo(); Supplier<MyInfo> s3 = MyInfo::new; } ``` 1. **`Supplier<MyInfo> s1 = () -> new MyInfo("Alien", 170, 65);` 說明**: 此處的參數列表不匹配,因為 Supplier 介面是一個無參界面,而建構函數 `MyInfo(String name, int height, int weight)` 需要三個參數。因此不能使用建構函式引用 2. **`Supplier<MyInfo> s2 = () -> new MyInfo();` 和 `Supplier<MyInfo> s3 = MyInfo::new;` 說明**: 這兩個範例中使用了無參構造器,符合 Supplier 介面的無參要求,因此可以使用建構子來參考 `MyInfo::new` 來取代 Lambda 表達式 `() -> new MyInfo()` ### 數組引用 Array References * 數組引用(`Array References`)是一種方法引用,允許你使用簡單的語法來創建數組 它使用類似於構造函數引用的語法,即 `Type[]::new`,並且需要與目標函數接口的參數列表相匹配… 這種方法引用可以使代碼更加簡潔和易讀 範例如下: ```java= public static void TestMethodArray() { MyInfo[] m = new MyInfo[3]; // Java 原型 Function<Integer, MyInfo[]> function = new Function<Integer, MyInfo[]>() { @Override public MyInfo[] apply(Integer integer) { return new MyInfo[integer]; } }; // 1. Lambda 原型 Function<Integer, MyInfo[]> function1 = integer -> new MyInfo[integer]; // 2. 數組引用 Function<Integer, MyInfo[]> function2 = MyInfo[]::new; } ``` 1. **Lambda 原型** * 使用 Lambda 表達式來簡化匿名內部類的寫法,這段程式碼與上述匿名內部類的功能相同 * `integer -> new MyInfo[integer]` 是 Lambda 表達式,根據傳入的 integer 參數來創建一個新的 MyInfo 數組 2. **數組引用** * 使用數組引用來進一步簡化 Lambda 表達式,這是一種特殊的構造函數引用語法,用於創建數組 * `MyInfo[]::new` 是數組引用,根據傳入的 integer 參數來創建一個新的 MyInfo 數組 ## Appendix & FAQ :::info 是簡短了不少的代碼量,不過這要好好熟悉,不然不建議使用,因為**可讀性差** ::: ###### tags: `Java 基礎進階`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully