<?xml version="1.0" encoding="utf-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>TriLe.dev</title><link>https://trile.dev/</link><description>Personal Technology Blog - TriLe.Dev</description><generator>Hugo 0.109.0 https://gohugo.io/</generator><language>en</language><managingEditor>contact@trile.dev (Tri Le)</managingEditor><webMaster>contact@trile.dev (Tri Le)</webMaster><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><lastBuildDate>Sat, 12 Jul 2025 09:17:46 +0000</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://trile.dev/rss.xml"/><item><title>Identify Responsibilities and Boundaries: The Key to design a Loose Coupling and High Cohesion system</title><link>https://trile.dev/post/2024-02-03-identify-responsibilities-and-boundaries-the-key-to-design-a-loose-coupling-and-high-cohesion-system/</link><guid isPermaLink="true">https://trile.dev/post/2024-02-03-identify-responsibilities-and-boundaries-the-key-to-design-a-loose-coupling-and-high-cohesion-system/</guid><pubDate>Sat, 03 Feb 2024 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Loose coupling and high cohesion are two fundamental principles in software design that are often discussed but it&amp;rsquo;s difficult.
After many failures, I believe I have found the key to solving the above problem: clearly defining the responsibilities and boundaries of each component. In this article, I will explain why this is a crucial step and provide practical guidance on how to achieve it.&lt;/p>
&lt;h2 id="1-whatre-coupling-and-cohesion">1. What&amp;rsquo;re Coupling and Cohesion?&lt;/h2>
&lt;blockquote>
&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Cohesion_(computer_science)">Cohesion&lt;/a> is the degree to which the elements inside a module belong together.&lt;/p>
&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)">Coupling&lt;/a> is the degree of interdependence between software modules.&lt;/p>
&lt;/blockquote>
&lt;p>Although the above two definitions are talking about modules, in my experience it ranges from system architecture, to components to classes.
I have mentioned its benefits when applied in system architecture in the article &lt;a href="https://trile.dev/post/2024-01-21-the-importance-of-modularity-and-ddd-in-system-architecture/">The Importance of Modularity and DDD in System Architecture
&lt;/a> and &lt;strong>DDD is the tool that helps us do it&lt;/strong>.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/cohesion-coupling.svg" alt="Identify Responsibilities and Boundaries">&lt;/p>
&lt;h2 id="2-identifying-responsibilities-and-boundaries">2. Identifying Responsibilities and Boundaries&lt;/h2>
&lt;p>To create a loosely coupled and highly cohesive system, it’s critical to identify the responsibilities and boundaries of each module and component. Here’s how to approach this at different levels:&lt;/p>
&lt;h4 id="21-applying-responsibility-and-boundaries-at-the-domain-level">2.1. Applying Responsibility and Boundaries at the Domain Level&lt;/h4>
&lt;p>When designing at the System Architecture level, a domain-based structure is often the most effective approach, especially for large systems with multiple business domains. Domain-Driven Design (DDD) is particularly valuable here, as it encourages breaking down a complex system into smaller, independent domains with clearly defined responsibilities. This reduces interdependencies and keeps each domain focused on its unique purpose, which naturally leads to a more cohesive and loosely coupled system.&lt;/p>
&lt;h4 id="22-single-responsibility">2.2. Single Responsibility&lt;/h4>
&lt;p>The Single Responsibility Principle is a guiding force behind well-defined modules. Each component, whether it’s a module, class, or function, should have one and only one responsibility. This clear delineation not only ensures that each module is cohesive but also reduces the chance of introducing unintended side effects when making changes. In practice, this means every module should serve a distinct purpose without overlapping with others.&lt;/p>
&lt;h4 id="23-interface-dependency">2.3 Interface Dependency&lt;/h4>
&lt;p>To maintain loose coupling, we need to be mindful of interface dependency. By designing interactions between components around well-defined interfaces, we prevent tightly coupling our system to specific implementations. This is particularly important when working across domains or when modules need to evolve independently. Through dependency inversion and interface-driven design, components can collaborate without being tightly coupled, enhancing the system&amp;rsquo;s modularity.&lt;/p>
&lt;h2 id="3-who-will-identify-responsibilities-and-boundaries">3. Who will identify responsibilities and boundaries?&lt;/h2>
&lt;p>Responsibility definition isn’t a one-person job; it involves collaboration across roles to ensure alignment at various levels:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Solution Architect&lt;/strong>: For the system level, the Solution Architect defines boundaries across domains and ensures alignment with business goals.&lt;/li>
&lt;li>&lt;strong>Tech Lead &amp;amp; Developers&lt;/strong>: At the domain and component level, Tech Leads and Developers take responsibility for identifying boundaries within each domain. They focus on the practical implementation of modularization and are instrumental in maintaining a cohesive design.&lt;/li>
&lt;li>&lt;strong>Developers&lt;/strong>: At the level of modules, packages, and classes, individual developers ensure that each element serves its single responsibility, maintaining both loose coupling and high cohesion in the codebase.
This layered approach ensures that boundaries and responsibilities are clearly defined and maintained at every level, making it easier to achieve a modular, flexible, and scalable system.&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://trile.dev/img/identify-resposibility-roles.svg" alt="Who identifies responsibilities and boundaries?">&lt;/p>
&lt;p>&lt;em>Note: The image above shows responsibilities at each level, responsibilities according to each level. Solution Architecture for system level, Tech Lead and Developer for the domain level, Developer for components-modules, packages, classes.&lt;/em>&lt;/p>
&lt;h2 id="4-conclusion">4. Conclusion&lt;/h2>
&lt;blockquote>
&lt;p>Everything in software architecture is a trade-off. &lt;br>
— &lt;cite>&lt;a href="https://www.amazon.com/Fundamentals-Software-Architecture-Comprehensive-Characteristics/dp/1492043451/">Mark Richards and Neal Ford - Fundamentals of Software Architecture: An Engineering Approach&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Identifying responsibilities and boundaries within a system requires significant time, effort, and collaboration, and there’s always a risk of failure. However, the rewards for successfully implementing these principles are substantial. &lt;strong>A system with well-defined boundaries and responsibilities is easier to maintain, more resilient to change, and allows for a level of flexibility that’s essential in complex, evolving systems&lt;/strong>.&lt;/p>
&lt;p>In short, while defining responsibilities and boundaries may be challenging, the investment is well worth it. A loosely coupled and highly cohesive system not only supports current needs but also prepares you for future growth and adaptability. By taking the time to structure your system around these principles, you’re setting the stage for long-term success.&lt;/p>
&lt;h6 id="ReferenceArticles">Reference links&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/">Cohesion and Coupling: the difference&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://edwardthienhoang.wordpress.com/2018/01/08/low-coupling-and-high-cohesion/">LOW COUPLING VÀ HIGH COHESION LÀ GÌ?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.ttulka.com/how-cohesion-and-coupling-correlate/">How Cohesion and Coupling Correlate&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.baeldung.com/cs/cohesion-vs-coupling/">Difference Between Cohesion and Coupling&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Thank you for reading this far.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/system-architecture/">System Architecture</category><category domain="https://trile.dev/tags/modularity/">modularity</category><category domain="https://trile.dev/tags/ddd/">ddd</category><category domain="https://trile.dev/tags/system-architecture/">system-architecture</category></item><item><title>The Importance of Modularity and DDD in System Architecture</title><link>https://trile.dev/post/2024-01-21-the-importance-of-modularity-and-ddd-in-system-architecture/</link><guid isPermaLink="true">https://trile.dev/post/2024-01-21-the-importance-of-modularity-and-ddd-in-system-architecture/</guid><pubDate>Sun, 21 Jan 2024 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>When used Modularity and Domain-Driven Design (DDD) together, they can help to create systems that are easier to maintain, more reliable, and more adaptable to change.&lt;/p>
&lt;h2 id="modularity">Modularity&lt;/h2>
&lt;p>Modularity is an architectural characteristic that refers to the system being divided into smaller, independent components. These components can be developed, tested, deployed, and maintained independently, improving the efficiency and scalability of the system.&lt;/p>
&lt;p>Modularity is closely related to other architectural characteristics, including:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Testability:&lt;/strong> Modularity improves the testability of the system by allowing components to be tested individually. This helps to reduce the time and cost of testing, as well as improve the quality of the system.&lt;/li>
&lt;li>&lt;strong>Configurability:&lt;/strong> Modularity improves the configurability of the system by allowing components to be configured independently. This helps the system to meet the different requirements of users in a flexible way.&lt;/li>
&lt;li>&lt;strong>Flexibility:&lt;/strong> Modularity improves the flexibility of the system by allowing components to be changed or extended easily. This helps the system to adapt to changes in the environment or the needs of users.&lt;/li>
&lt;li>&lt;strong>Agility:&lt;/strong> Modularity improves the agility of the system by allowing components to be developed and deployed quickly. This helps the system to meet changing requirements in a timely manner.&lt;/li>
&lt;li>&lt;strong>Maintainability:&lt;/strong> Modularity improves the maintainability of the system by making the system easier to understand and repair. This helps to reduce the time and cost of maintenance, as well as improve the reliability of the system.&lt;/li>
&lt;/ul>
&lt;h2 id="ddd">DDD&lt;/h2>
&lt;p>DDD is a software design approach that focuses on understanding and modeling business domains. DDD uses concepts such as entities, constraints, and services to create accurate and flexible software models.&lt;/p>
&lt;p>DDD can be combined with modularity to create systems with high maintainability. By dividing the system into smaller, independent components, developers can easily understand and repair DDD models.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/modularity-with-ddd.svg" alt="Modularity + DDD = Time To Market">&lt;/p>
&lt;h2 id="how-to-combine-modularity-with-ddd">How to Combine Modularity with DDD&lt;/h2>
&lt;p>To combine modularity with DDD, developers can use the following principles:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Split entities, constraints, and services into separate components.&lt;/strong> This helps to make DDD models easier to understand and manage.&lt;/li>
&lt;li>&lt;strong>Use interfaces to connect components.&lt;/strong> This helps to make components reusable and flexible.&lt;/li>
&lt;li>&lt;strong>Use common data structures and algorithms for similar components.&lt;/strong> This helps to reduce duplication and improve maintainability.&lt;/li>
&lt;/ul>
&lt;!-- ## Example
Imagine a customer relationship management system. This system can be divided into the following components:
* **Entities:** Customers, orders, products
* **Constraints:** Authentication, consistency, availability
* **Services:** Create customer, update customer, delete customer
These components can be divided into separate modules as follows:
* **Entities:** The entity module contains all the entities in the system.
* **Constraints:** The constraint module contains all the constraints in the system.
* **Services:** The service module contains all the services in the system.
Each module can be developed, tested, and deployed independently. This helps to improve the maintainability of the system. -->
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Modularity and DDD are two important techniques that can be combined to create systems with high maintainability. By dividing the system into smaller, independent components, developers can easily understand and repair DDD models.&lt;/p>
&lt;h6 id="ReferenceArticles">Reference links&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://massimo-nazaria.github.io/testability-modularity.html">Testability = Modularity&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.modularmanagement.com/blog/accelerate-agility-flexibility-and-efficiency-with-modular-design">Accelerate Agility, Flexibility and Efficiency with Modular Design&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.thereformedprogrammer.net/my-experience-of-using-modular-monolith-and-ddd-architectures/">My experience of using modular monolith and DDD architectures&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://javascript.plainenglish.io/domain-driven-design-for-a-modular-monolith-bridging-the-gap-between-microservices-and-monoliths-2d2521196dd8">Domain-Driven Design for a Modular Monolith: Bridging the Gap Between Microservices and Monoliths&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Thank you for reading this far.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/system-architecture/">System Architecture</category><category domain="https://trile.dev/tags/modularity/">modularity</category><category domain="https://trile.dev/tags/ddd/">ddd</category><category domain="https://trile.dev/tags/system-architecture/">system-architecture</category></item><item><title>Kotlin Coroutines vs LMAX Disruptor: Benchmarking for Asynchronous and Concurrent Programming</title><link>https://trile.dev/post/2023-05-06-kotlin-coroutines-vs-lmax-disruptor-benchmarking-for-asynchronous-and-concurrent-programming/</link><guid isPermaLink="true">https://trile.dev/post/2023-05-06-kotlin-coroutines-vs-lmax-disruptor-benchmarking-for-asynchronous-and-concurrent-programming/</guid><pubDate>Sat, 06 May 2023 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Asynchronous and concurrent programming are critical for building high-performance and scalable applications. But with so many tools available, it can be challenging to choose the right one for the job. In the JVM ecosystem, Kotlin &lt;a href="https://trile.dev/tags/coroutines/">Coroutines&lt;/a> and LMAX Disruptor are two popular options for asynchronous and concurrent programming. But which one is better?&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/kotlin-coroutines-vs-lmax-disruptor.png" alt="Kotlin Coroutines vs LMAX Disruptor">&lt;/p>
&lt;h3 id="introduction">Introduction&lt;/h3>
&lt;p>Kotlin &lt;a href="https://trile.dev/tags/coroutines/">Coroutines&lt;/a> is a lightweight and expressive library for writing asynchronous, non-blocking code in Kotlin. It provides an easy-to-understand way to write concurrent programs. On the other hand, &lt;a href="https://lmax-exchange.github.io/disruptor/">LMAX Disruptor&lt;/a> is a high-performance inter-thread communication library for the JVM that provides a fast and efficient way to pass data between threads. It&amp;rsquo;s worth noting that LMAX Disruptor is used as the underlying communication mechanism in many high-performance systems, including the logging framework &lt;a href="https://logging.apache.org/log4j/">Log4j2&lt;/a>.&lt;/p>
&lt;p>To help developers choose the best tool for their specific use case, I conducted a benchmarking project on &lt;a href="https://github.com/thanhtrixx/concurrency-library-benchmark">thanhtrixx/concurrency-library-benchmark (github.com)&lt;/a> that compares the performance of Kotlin Coroutines and LMAX Disruptor. The project uses the &lt;a href="https://trile.dev/tags/jmh/">Java Microbenchmark Harness (JMH)&lt;/a> for accurate and reliable performance measurements. The benchmark measures the time it takes for a large number of events to be processed by each library.&lt;/p>
&lt;h3 id="BenchmarkingProcess">Benchmarking Process&lt;/h3>
&lt;p>To ensure accurate and reliable performance measurements, the project uses the Java Microbenchmark Harness (JMH). My benchmarking project measures the time it takes for a large number of events to be processed by each library. I compare the performance of Kotlin Coroutines and LMAX Disruptor, and then provide results that can help developers choose the best tool for their specific use case.&lt;/p>
&lt;h3 id="BenchmarkResults">Benchmark Results&lt;/h3>
&lt;p>After running the benchmark, the results will be generated in the result directory. For a fair comparison between the two libraries, these results can be visualized using &lt;a href="https://jmh.morethan.io/">https://jmh.morethan.io/&lt;/a>.&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://jmh.morethan.io/?gist=e14ce0b67bfd95ab47e974fa36d2ae8f">Lmax-Disruptor vs Kotlin Coroutines: bufferSize = [512], numberEvent=[20, 10000, 100000] with GC info&lt;/a>
&lt;img src="https://trile.dev/img/post/bufferSize-512-numberEvent-20-10000-100000.png" alt="Lmax-Disruptor vs Kotlin Coroutines: bufferSize = [512], numberEvent=[20, 10000, 100000] with GC info">&lt;/li>
&lt;li>&lt;a href="https://jmh.morethan.io/?gist=3bd4037a941da944fe3a578ee2fe5fb6">Lmax-Disruptor vs Kotlin Coroutines: bufferSize = [128, 512, 1024], numberEvent=[100, 1000, 10000, 20000]&lt;/a>
&lt;img src="https://trile.dev/img/post/bufferSize-128-512-1024-numberEvent-100-1000-100000-200000.png" alt="Lmax-Disruptor vs Kotlin Coroutines: bufferSize = [128, 512, 1024], numberEvent=[100, 1000, 10000, 20000]">&lt;/li>
&lt;/ul>
&lt;h3 id="Conclusion">Conclusion&lt;/h3>
&lt;p>Based on the benchmark results, Kotlin Coroutines is the better choice for applications where high throughput is essential. However, LMAX Disruptor may be more suitable for memory-constrained environments. Ultimately, the choice between the two libraries depends on the specific requirements of the application and the trade-offs the developer is willing to make.
This benchmarking project can help developers make informed decisions when choosing a tool for asynchronous and concurrent programming. If you&amp;rsquo;re interested in contributing to this project or have any questions, please reach me to the project maintainers. I always looking for ways to improve the benchmark and make it more comprehensive.
In conclusion, Kotlin Coroutines and LMAX Disruptor are both excellent tools for asynchronous and concurrent programming. Understanding their strengths and weaknesses is crucial in making the right choice for your application.&lt;/p>
&lt;h6 id="ReferenceArticles">Reference links&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://github.com/thanhtrixx/concurrency-library-benchmark">thanhtrixx/concurrency-library-benchmark (github.com)&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kotlinlang.org/docs/coroutines-overview.html">Coroutines&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://lmax-exchange.github.io/disruptor/">LMAX Disruptor&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/openjdk/jmh">openjdk/jmh: https://openjdk.org/projects/code-tools/jmh (github.com)&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Thank you for reading this far.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/kotlin/">Kotlin</category><category domain="https://trile.dev/categories/coroutines/">Coroutines</category><category domain="https://trile.dev/series/compare/">Compare</category><category domain="https://trile.dev/tags/kotlin/">kotlin</category><category domain="https://trile.dev/tags/coroutines/">coroutines</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/jmh/">jmh</category><category domain="https://trile.dev/tags/performance/">performance</category><category domain="https://trile.dev/tags/lmax-disruptor/">lmax-disruptor</category><category domain="https://trile.dev/tags/concurrent-programming/">concurrent-programming</category></item><item><title>Comparing Git Flow, Trunk Based and GitHub Flow</title><link>https://trile.dev/post/2023-05-02-compare-git-flow-trunk-based-and-github-flow/</link><guid isPermaLink="true">https://trile.dev/post/2023-05-02-compare-git-flow-trunk-based-and-github-flow/</guid><pubDate>Tue, 02 May 2023 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Việc quản lý mã nguồn là rất quan trọng để đảm bảo tính ổn định và hiệu quả của dự án. Hiện nay, có nhiều phương pháp quản lý mã nguồn khác nhau như: Github Flow, Git Flow và Trunk Based. Trong bài viết này, chúng ta sẽ đi vào chi tiết về các phương pháp quản lý mã nguồn này và tìm hiểu xem phương pháp nào phù hợp nhất cho feature team size từ 2 đến 7 người trong giai đoạn phát triển tính năng cho ứng dụng.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/github-flow-max.png" alt="GitHub Flow-logo">&lt;/p>
&lt;h3 id="GitFlow">1. Git Flow&lt;/h3>
&lt;p>Git Flow là một phương pháp quản lý phiên bản và quản lý mã nguồn được đưa ra bởi Vincent Driessen. Phương pháp này bao gồm hai nhánh chính là &amp;ldquo;develop&amp;rdquo; và &amp;ldquo;master&amp;rdquo;. Nhánh &amp;ldquo;develop&amp;rdquo; được sử dụng để phát triển tính năng mới và sửa lỗi, trong khi nhánh &amp;ldquo;master&amp;rdquo; được sử dụng để lưu trữ phiên bản ổn định. Trong Git Flow, mỗi tính năng mới được phát triển trên một nhánh riêng biệt, được tách ra từ nhánh &amp;ldquo;develop&amp;rdquo;. Sau khi tính năng được hoàn thành, nó sẽ được merge lại vào nhánh &amp;ldquo;develop&amp;rdquo;. Sau đó, nhánh &amp;ldquo;develop&amp;rdquo; sẽ được merge vào nhánh &amp;ldquo;master&amp;rdquo; để tạo ra một phiên bản mới và được triển khai.&lt;/p>
&lt;p>Mặc dù Git Flow là một phương pháp quản lý phiên bản và quản lý mã nguồn phổ biến, nhưng nó có một số hạn chế đối với các dự án có tính chất phát triển nhanh, đòi hỏi sự linh hoạt và tốc độ cao. Với Git Flow, mỗi tính năng đều phải được tạo ra trên một nhánh mới, điều này có thể dẫn đến sự rối loạn và khó khăn trong việc quản lý các nhánh.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/git-flow-diagram.svg" alt="Ví dụ Git Flow">&lt;/p>
&lt;h3 id="TrunkBased">2. Trunk Based&lt;/h3>
&lt;p>Trunk Based là một phương pháp quản lý phiên bản và quản lý mã nguồn đơn giản, được sử dụng bởi các công ty có quy mô lớn và đòi hỏi tốc độ cao như Google và Facebook. Trong phương pháp này, tất cả các tính năng mới đều được phát triển trên một nhánh chính là &amp;ldquo;trunk&amp;rdquo;, và được đẩy lên server liên tục.&lt;/p>
&lt;p>Trong Trunk Based, các tính năng mới không được tách ra thành các nhánh riêng biệt như Git Flow, mà được phát triển trên một nhánh chính duy nhất. Sau đó, tính năng mới được đẩy lên server ngay khi hoàn thành, và được triển khai ngay lập tức. Phương pháp này giúp giảm thiểu thời gian chờ đợi và giảm bớt sự rối loạn của các nhánh. Tuy nhiên, phương pháp Trunk Based có một số hạn chế đối với các dự án có quy mô lớn và nhiều tính năng phức tạp hoặc các dự án chưa ổn định, khi đó sự đồng bộ hóa và kiểm soát chất lượng của mã nguồn trở nên khó khăn.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/trunk-based-diagram.svg" alt="Ví dụ Trunk Based">&lt;/p>
&lt;h3 id="GitHubFlow">3. GitHub Flow&lt;/h3>
&lt;p>GitHub Flow là một phương pháp quản lý phiên bản và quản lý mã nguồn đơn giản và linh hoạt, được sử dụng bởi GitHub. Phương pháp này bao gồm ba giai đoạn: tạo nhánh, phát triển tính năng, và triển khai. Khi bắt đầu phát triển tính năng mới, người dùng sẽ tạo ra một nhánh mới từ nhánh chính, và đặt tên theo tính năng đó. Sau đó, họ sẽ phát triển tính năng mới trên nhánh đó. Khi hoàn thành, họ sẽ tạo ra một yêu cầu pull request (PR) để đề xuất tính năng mới được merge vào nhánh chính. Trước khi merge, tính năng mới sẽ được kiểm tra và đảm bảo tính ổn định. Sau khi merge thành công, tính năng mới sẽ được triển khai.&lt;/p>
&lt;p>Phương pháp GitHub Flow có nhiều ưu điểm, đặc biệt là tính đơn giản và linh hoạt. Với phương pháp này, mỗi tính năng mới được phát triển trên một nhánh riêng biệt, tương tự như Git Flow, nhưng không có sự rắc rối của các nhánh. Ngoài ra, phương pháp này cũng giúp đảm bảo tính ổn định của mã nguồn trước khi merge, giúp giảm thiểu sự cố xảy ra sau khi triển khai. Tuy nhiên, phương pháp này có thể gây ra sự cố khi quá nhiều tính năng mới được phát triển trên nhánh chính cùng một lúc, và không có sự đồng bộ hóa đầy đủ giữa các tính năng đang phát triển.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/git-hub-flow-diagram.svg" alt="Ví dụ GitHub Flow">&lt;/p>
&lt;h3 id="Conclusion">4. Conclusion&lt;/h3>
&lt;p>GitHub Flow là phương pháp vừa đơn giản vừa linh hoạt và phù hợp cho các feature team size từ 2 đến 7 người trong giai đoạn phát triển tính năng cho ứng dụng. Điều này là do phương pháp này có tính chất tách biệt giữa các tính năng, và giúp đảm bảo tính ổn định của mã nguồn trước khi triển khai. Ngoài ra, phương pháp này giúp giảm thiểu sự cố xảy ra sau khi triển khai, đồng thời giảm thiểu sự rối loạn của các nhánh.&lt;/p>
&lt;p>Điểm khác biệt chính giữa GitHub Flow và Git Flow là cách quản lý các nhánh. Trong GitHub Flow, mỗi tính năng được phát triển trên một nhánh riêng biệt và được merge vào nhánh chính sau khi đã được kiểm tra và đảm bảo tính ổn định. Trong khi đó, trong Git Flow, các tính năng được phát triển trên các nhánh feature riêng biệt, sau đó được merge vào nhánh develop để kiểm tra tính ổn định, và sau đó mới merge vào nhánh release và master để triển khai.&lt;/p>
&lt;p>Trong trường hợp của Trunk Based, tất cả các tính năng được phát triển trên cùng một nhánh chính (trunk) và các thay đổi được commit trực tiếp vào nhánh chính. Tuy nhiên, đây không phải là phương pháp tốt nhất cho các dự án đang trong giai đoạn phát triển tính năng.&lt;/p>
&lt;p>Lý do là Trunk Based là một phương pháp rất rủi ro, vì nó không cho phép kiểm soát chặt chẽ các thay đổi trước khi triển khai. Nếu một lỗi xuất hiện trên nhánh chính, nó có thể gây ảnh hưởng đến tất cả các tính năng khác đang được phát triển trên nhánh đó. Điều này có thể dẫn đến các vấn đề về tính ổn định và khả năng triển khai của ứng dụng. Ngoài ra, khi có nhiều tính năng đang được phát triển trên cùng một nhánh, sẽ khó khăn hơn để quản lý và theo dõi các thay đổi và sẽ tạo ra nhiều xung đột khi merge các tính năng khác nhau.&lt;/p>
&lt;p>Vì vậy, GitHub Flow được coi là phương pháp phù hợp nhất cho các feature team size từ 2 đến 7 người trong giai đoạn phát triển tính năng cho ứng dụng. Với GitHub Flow, các tính năng được phát triển trên các nhánh riêng biệt và được merge vào nhánh chính sau khi đã được kiểm tra và đảm bảo tính ổn định. Điều này giúp đảm bảo rằng các thay đổi không ảnh hưởng đến các tính năng khác và giúp giảm thiểu các xung đột khi merge.&lt;/p>
&lt;p>Tóm lại, trong quá trình phát triển tính năng cho ứng dụng, có nhiều phương pháp quản lý mã nguồn khác nhau như Git Flow, Trunk Based và GitHub Flow. Mỗi phương pháp có những ưu điểm và nhược điểm riêng và phù hợp với các kích thước và giai đoạn của dự án khác nhau. Trong trường hợp của các feature team size từ 2 đến 7 người trong giai đoạn phát triển tính năng cho ứng dụng, GitHub Flow được coi là phương pháp phù hợp nhất với tính chất tách biệt giữa các tính năng và giúp đảm bảo tính ổn định của mã nguồn trước khi triển khai.&lt;/p>
&lt;h6 id="ReferenceArticles">Reference articles&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://gaboesquivel.com/blog/2018/recommendations-to-enhance-your-github-flow/">Recommendations to Enhance your Github Flow&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://build5nines.com/introduction-to-git-version-control-workflow/">Introduction to Git Version Control Workflow&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.alexhyett.com/git-flow-github-flow/">Git Flow vs GitHub Flow&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://georgestocker.com/2020/03/04/please-stop-recommending-git-flow/">Please stop recommending Git Flow!&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.kinto-technologies.com/posts/2023-03-07-From-Git-flow-to-GitHub-flow/">From Git-flow to GitHub-flow&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Cảm ơn các bạn đã đọc tới đây.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/series/software-development/">Software Development</category><category domain="https://trile.dev/tags/github-flow/">github-flow</category><category domain="https://trile.dev/tags/git-flow/">git-flow</category><category domain="https://trile.dev/tags/trunk-based/">trunk-based</category><category domain="https://trile.dev/tags/source-code-management/">source-code-management</category><category domain="https://trile.dev/tags/version-control/">version-control</category></item><item><title>Parameterized Test in JUnit 5</title><link>https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/</link><guid isPermaLink="true">https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/</guid><pubDate>Sat, 15 Aug 2020 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Nếu các bạn đã thực hiện &lt;code>unit test&lt;/code> với &lt;a href="https://junit.org/junit4/">JUnit4&lt;/a> có một điểm yếu là không hỗ trợ &lt;code>parameters&lt;/code> cho &lt;code>test method&lt;/code> dẫn tới việc phải dupl code rất nhiều gây khó khăn cho việc review, update &lt;code>test case&lt;/code> 👎. Điểm yếu này có thể khắc phục bằng &lt;a href="https://testng.org">TestNG&lt;/a>. Rất may, &lt;a href="https://junit.org/junit5/">JUnit5&lt;/a> ra đời với nhiều cải tiến, trong đó &lt;code>Parameterized Test&lt;/code> là cải tiến giúp ta khắc phục được điểm yếu trên ❤️.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/junit5.png" alt="JUnit5-logo">&lt;/p>
&lt;h3 id="RequiredSetup">Required Setup&lt;/h3>
&lt;p>Để sử dụng &lt;code>Parameterized Tests&lt;/code> ta cần dependency là &lt;code>junit-jupiter-params&lt;/code>.&lt;/p>
&lt;p>Với &lt;code>Gradle&lt;/code> ta thêm:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">testImplementation&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;org.junit.jupiter:junit-jupiter-params:5.7.1&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Với &lt;code>Maven&lt;/code> ta thêm:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>org.junit.jupiter&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>junit-jupiter-params&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;version&amp;gt;&lt;/span>5.7.1&lt;span class="nt">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;scope&amp;gt;&lt;/span>test&lt;span class="nt">&amp;lt;/scope&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="ArgumentSources">Argument Sources&lt;/h3>
&lt;p>Các tham số của &lt;code>Parameterized Tests&lt;/code> được cung cấp bởi các &lt;code>Argument Sources&lt;/code> sau:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#ValueSource">&lt;code>@ValueSource&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#EnumSource">&lt;code>@EnumSource&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#MethodSource">&lt;code>@MethodSource&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#CsvSource">&lt;code>@CsvSource&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#CsvFileSource">&lt;code>@CsvFileSource&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#ArgumentsSource">&lt;code>@ArgumentsSource&lt;/code>&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="ValueSource">@ValueSource&lt;/h3>
&lt;p>Là cách đơn giản nhất để cung cấp data test cho &lt;code>Parameterized Tests&lt;/code>. Cách này chỉ hỗ trợ các kiểu &lt;code>literal&lt;/code> sau:&lt;/p>
&lt;ul>
&lt;li>short&lt;/li>
&lt;li>byte&lt;/li>
&lt;li>int&lt;/li>
&lt;li>long&lt;/li>
&lt;li>float&lt;/li>
&lt;li>double&lt;/li>
&lt;li>char&lt;/li>
&lt;li>boolean&lt;/li>
&lt;li>java.lang.String&lt;/li>
&lt;li>java.lang.Class&lt;/li>
&lt;/ul>
&lt;p>Ví dụ sau sẽ test hàm &lt;code>String.isNullOrBlank&lt;/code> với 6 trường hợp được liệt kê ở &lt;code>@ValueSource&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="hl">&lt;span class="lnt">4
&lt;/span>&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{index} - String.isNullOrBlank() of [{0}]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@EmptySource&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@NullSource&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@ValueSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">strings&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\t&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test isNullOrBlank`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertTrue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isNullOrBlank&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Và để test 2 trường hợp đặc biệt &lt;code>null&lt;/code> và &lt;code>empty&lt;/code> ta có thể sử dụng &lt;code>@NullSource&lt;/code> và &lt;code>@EmptySource&lt;/code> hoặc dùng &lt;code>@NullAndEmptySource&lt;/code>.&lt;/p>
&lt;h3 id="EnumSource">@EnumSource&lt;/h3>
&lt;p>Để test với data test là &lt;code>enum&lt;/code>. Mặc định data test là tất cả các giá trị thuộc &lt;code>enum&lt;/code>. Trường hợp chỉ muốn test một vài giá trị trong &lt;code>enum&lt;/code> ta có thể làm giống ví dụ.&lt;/p>
&lt;p>Ví dụ kiểm tra những tháng 4, 6, 9 và 11 có 30 ngày thuộc &lt;code>enum&lt;/code> &lt;code>Month&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="hl">&lt;span class="lnt">2
&lt;/span>&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{index} - [{0}] have 30 day&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@EnumSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">value&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="k">class&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">names&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;APRIL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;JUNE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;SEPTEMBER&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;NOVEMBER&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test month have 30 day`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">month&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">isALeapYear&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">30&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">month&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isALeapYear&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="MethodSource">@MethodSource&lt;/h3>
&lt;p>&lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#ValueSource">&lt;code>@ValueSource&lt;/code>&lt;/a> và &lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#EnumSource">&lt;code>@EnumSource&lt;/code>&lt;/a> chỉ có thể cung cấp các data test đơn giản. Những trường hợp phức tạp ta có thể &lt;code>factory method&lt;/code> để cung cấp data test. Một lưu ý là &lt;code>factory method&lt;/code> phải là &lt;code>static&lt;/code>.&lt;/p>
&lt;p>Ví dụ này mình sẽ tối ưu so với bài &lt;a href="https://trile.dev/post/2020-07-31-use-mock-to-make-unit-test-easy#ExampleUnitTestWithMock">Use Mock to make Unit Test easy&lt;/a> với chỉ một &lt;code>test method&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="hl">&lt;span class="lnt"> 2
&lt;/span>&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{0} - {1} -&amp;gt; {2}&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@MethodSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;provideToTestData&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test getFullNameCustomerWithTotalBuyPriceGreaterThan`&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expected&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">&amp;gt;,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mockReturn&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Customer&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">totalBuyPrice&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">every&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customerRepository&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="n">returns&lt;/span> &lt;span class="n">mockReturn&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expected&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customerService&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">getFullNameCustomerWithTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">exactly&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">customerRepository&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">totalBuyPrice&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>và data test sẽ được cung cấp qua:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="hl">&lt;span class="lnt"> 1
&lt;/span>&lt;/span>&lt;span class="hl">&lt;span class="lnt"> 2
&lt;/span>&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line hl">&lt;span class="cl"> &lt;span class="k">companion&lt;/span> &lt;span class="k">object&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@JvmStatic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">provideToTestData&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nc">Stream&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nc">Arguments&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Empty list&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">emptyList&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">&amp;gt;(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">emptyList&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Customer&lt;/span>&lt;span class="p">&amp;gt;()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nc">Arguments&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;One customer&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Tri Le&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">firstName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Tri&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lastName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Le&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nc">Arguments&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Two customers&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Tri Le&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Anna Wesley&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">firstName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Tri&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lastName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Le&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">firstName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Anna&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lastName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Wesley&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Lưu ý:&lt;/strong> data trả về của &lt;code>factory method&lt;/code> phải là &lt;code>Stream&lt;/code> của các &lt;code>Arguments&lt;/code>. Tuy nhiên &lt;code>JUnit5&lt;/code> có hỗ trợ các kiểu khác như:&lt;/p>
&lt;ul>
&lt;li>&lt;code>DoubleStream&lt;/code>&lt;/li>
&lt;li>&lt;code>LongStream&lt;/code>&lt;/li>
&lt;li>&lt;code>IntStream&lt;/code>&lt;/li>
&lt;li>&lt;code>Collection&lt;/code>&lt;/li>
&lt;li>&lt;code>Iterator&lt;/code>&lt;/li>
&lt;li>&lt;code>Iterable&lt;/code>&lt;/li>
&lt;li>&lt;code>Một mảng của các objects&lt;/code>&lt;/li>
&lt;li>&lt;code>Một mảng của các primitives&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="CsvSource">@CsvSource&lt;/h3>
&lt;p>Data test sẽ được cung cấp bởi &lt;code>comma-separated values&lt;/code>&lt;/p>
&lt;p>Ví dụ sau kiểm tra hàm &lt;code>String.toUpperCase&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="hl">&lt;span class="lnt">2
&lt;/span>&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{index} - String.toUpperCase() of [{0}]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@CsvSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;trile,TRILE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;tRilE,TRILE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;trILE,TRILE&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test trim`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">expected&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">actual&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">toUpperCase&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expected&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">actual&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="CsvFileSource">@CsvFileSource&lt;/h3>
&lt;p>Tương tự như &lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#CsvSource">&lt;code>@CsvSource&lt;/code>&lt;/a> nhưng data test được load từ file.&lt;/p>
&lt;p>Ví dụ sau kiểm tra hàm &lt;code>String.toUpperCase&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="hl">&lt;span class="lnt">2
&lt;/span>&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{index} - String.toUpperCase() of [{0}]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@CsvFileSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">resources&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;/trim.csv&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">numLinesToSkip&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test trim csv file`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">expected&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">actual&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">toUpperCase&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expected&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">actual&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>với data test file:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-csv" data-lang="csv">str,expected
trile,TRILE
tRilE,TRILE
trILE,TRILE
&lt;/code>&lt;/pre>&lt;h3 id="ArgumentsSource">@ArgumentsSource&lt;/h3>
&lt;p>Cũng tương tự như &lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#MethodSource">&lt;code>@MethodSource&lt;/code>&lt;/a> nhưng data test được cung cấp bởi một &lt;code>implements class&lt;/code> của &lt;code>ArgumentsProvider&lt;/code> thay vì một &lt;code>factory method&lt;/code>. Cá nhân mình thấy &lt;a href="https://trile.dev/post/2020-08-15-parameterized-test-in-junit-5/#ArgumentsSource">&lt;code>@ArgumentsSource&lt;/code>&lt;/a> không tốt bằng&lt;/p>
&lt;p>Ví dụ test input argument khác &lt;code>null&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="hl">&lt;span class="lnt">2
&lt;/span>&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@ArgumentsSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">MyArgumentsProvider&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="k">class&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">testWithArgumentsSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">argument&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertNotNull&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">argument&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>data test được cung cấp bởi:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MyArgumentsProvider&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">ArgumentsProvider&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">override&lt;/span> &lt;span class="k">fun&lt;/span> &lt;span class="nf">provideArguments&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">context&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ExtensionContext&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">Stream&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="k">out&lt;/span> &lt;span class="n">Arguments&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nc">Stream&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;apple&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;banana&amp;#34;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">arguments&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nc">Arguments&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">of&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">arguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="CustomizingDisplayNames">Customizing Display Names&lt;/h3>
&lt;p>Một điểm yếu của &lt;code>Parameterized Tests&lt;/code> đó là hiển thị kết quả test không được rõ nghĩa lắm. Ví dụ như:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@EnumSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">value&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="k">class&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">names&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;APRIL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;JUNE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;SEPTEMBER&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;NOVEMBER&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test month have 30 day`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">month&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">isALeapYear&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">30&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">month&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isALeapYear&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>sẽ trả về kết quả sau (với &lt;code>Gradle&lt;/code> test report):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Test&lt;/th>
&lt;th>Method name&lt;/th>
&lt;th>Duration&lt;/th>
&lt;th>Result&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>[1] month=APRIL&lt;/td>
&lt;td>test month have 30 day(Month)[1]&lt;/td>
&lt;td>0.033s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>[2] month=JUNE&lt;/td>
&lt;td>test month have 30 day(Month)[2]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>[3] month=SEPTEMBER&lt;/td>
&lt;td>test month have 30 day(Month)[3]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>[4] month=NOVEMBER&lt;/td>
&lt;td>test month have 30 day(Month)[4]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>nhưng sẽ hơi tối nghĩa nên mình sẽ thay đổi chút như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="hl">&lt;span class="lnt">1
&lt;/span>&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kt" data-lang="kt">&lt;span class="line hl">&lt;span class="cl"> &lt;span class="nd">@ParameterizedTest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;#{index} - [{0}] have 30 day&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@EnumSource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">value&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="k">class&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">names&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;APRIL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;JUNE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;SEPTEMBER&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;NOVEMBER&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">`test month have 30 day`&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">month&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Month&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">isALeapYear&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">30&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">month&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">isALeapYear&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>thì kết quả sẽ đẹp hơn:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Test&lt;/th>
&lt;th>Method name&lt;/th>
&lt;th>Duration&lt;/th>
&lt;th>Result&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>#1 - [APRIL] have 30 day&lt;/td>
&lt;td>test month have 30 day(Month)[1]&lt;/td>
&lt;td>0.034s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>#2 - [JUNE] have 30 day&lt;/td>
&lt;td>test month have 30 day(Month)[2]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>#3 - [SEPTEMBER] have 30 day&lt;/td>
&lt;td>test month have 30 day(Month)[3]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>#4 - [NOVEMBER] have 30 day&lt;/td>
&lt;td>test month have 30 day(Month)[4]&lt;/td>
&lt;td>0.001s&lt;/td>
&lt;td>passed&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;ul>
&lt;li>&lt;code>{index}&lt;/code> là số thứ tự của các data test.&lt;/li>
&lt;li>&lt;code>{arguments}&lt;/code> danh sách tất cả các &lt;code>argument name&lt;/code> và &lt;code>argument value&lt;/code>.&lt;/li>
&lt;li>&lt;code>{0}&lt;/code>, &lt;code>{1}&lt;/code>, &amp;hellip; là &lt;code>argument value&lt;/code> theo thứ tự bắt đầu từ 0.&lt;/li>
&lt;/ul>
&lt;h6 id="ReferenceArticles">Reference articles&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests">JUnit 5 Parameterized Tests&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/">JUnit 5 Tutorial: Writing Parameterized Tests&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.baeldung.com/parameterized-tests-junit-5">Guide to JUnit 5 Parameterized Tests&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mkyong.com/junit5/junit-5-parameterized-tests/">JUnit 5 Parameterized Tests&lt;/a>&lt;/li>
&lt;/ul></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/categories/quality-assurance/">Quality Assurance</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/series/unit-test/">Unit Test</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/unit-test/">unit-test</category><category domain="https://trile.dev/tags/junit5/">junit5</category><category domain="https://trile.dev/tags/parameterized-test/">parameterized-test</category></item><item><title>Use Mock to make Unit Test easy</title><link>https://trile.dev/post/2020-07-31-use-mock-to-make-unit-test-easy/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-31-use-mock-to-make-unit-test-easy/</guid><pubDate>Fri, 31 Jul 2020 04:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Ở bài viết &lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/">How to Write Testable Code&lt;/a> có đề cập đế khái niệm &lt;code>Mock&lt;/code>. Vậy &lt;code>Mock&lt;/code> là gì? Và đặc biệt là các sử dụng nó dể thực hiện &lt;code>Unit Test&lt;/code> đơn giản hơn nhé.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/mockk-logo.png" alt="MockK-logo">&lt;/p>
&lt;h3 id="WhatsMock">What&amp;rsquo;s Mock&lt;/h3>
&lt;p>&lt;code>Mock&lt;/code> là một &lt;code>fake class&lt;/code> cho phép ta &lt;code>pre-programmed&lt;/code> ở bước &lt;code>runtime&lt;/code> nhằm giả lập phản ứng của &lt;code>fake class&lt;/code> đó với một lời gọi cụ thể nào đó. Ngoài ra &lt;code>Mock&lt;/code> còn cho phép ta &lt;code>verify&lt;/code> xem các method trong &lt;code>fake class&lt;/code> đã được gọi bao nhiêu lần.&lt;/p>
&lt;p>Chà! Định nghĩ nghe có vẻ khó hiểu quá!&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/SAAMcPRfQpgyI/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Mình sẽ ví dụ test case sau:&lt;/p>
&lt;blockquote>
&lt;p>Test một phương thức truy vấn thông tin khách hàng mua nhiều hơn 30 triệu từ Database&lt;/p>
&lt;/blockquote>
&lt;p>Khi đó ta có các vấn đề sau khi thực hiện &lt;code>Unit Test&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>Khi &lt;code>Unit Test&lt;/code> phải tạo connection tới Database hay sao? Trường hợp cho phép connection xuống Database lỡ có ai đó thay đổi Database thì sao?&lt;/li>
&lt;li>Làm sao để biết bên trong hàm thực sự truy vấn thông tin khách hàng mua nhiều hơn 30 triệu hay 29 triệu? Số lần gọi truy vấn xuống Database? Vì nếu ta chuẩn bị data trong Database không tốt có thể kết quả trả về của truy vấn 29tr và 30tr là như nhau, cũng như việc ta truy vấn xuống Database 2 lần trong một lần gọi cũng không thể biết vì kết quả trả về là như nhau.&lt;/li>
&lt;/ul>
&lt;p>Và khi này &lt;code>Mock&lt;/code> xuất hiện như một người hùng và giúp ta giải quyết các vấn đề trên.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/ek4CUx2FONgHaMz9V5/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Ngoài ví dụ trên &lt;code>Mock&lt;/code> còn có thể giúp ta trong các trường hợp sau:&lt;/p>
&lt;ul>
&lt;li>Đối tượng cung cấp thông tin không xác định. Như: &lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code#ConsistencyUnit">trả về số random&lt;/a>, thời gian hiện tại, thời tiết, nhiệt độ&amp;hellip;&lt;/li>
&lt;li>Đối tượng cung cấp thông tin qua database, web service, rpc, cache&amp;hellip;&lt;/li>
&lt;li>Đối tượng cần tính toán lâu, tốn resource&lt;/li>
&lt;li>Đối tượng chưa tồn tại hoặc có thể bị thay đổi. Như trong ví dụ trong bài &lt;a href="https://trile.dev/post/2020-03-15-custom-exception">Custom Exception&lt;/a> mình có thể thực hiện &lt;code>Unit Test&lt;/code> trước phần &lt;a href="https://trile.dev/post/2020-03-15-custom-exception#SalaryTransfer">SalaryTransfer&lt;/a> mà không phải đợi một bạn khác làm phần &lt;a href="https://trile.dev/post/2020-03-15-custom-exception#TransferMoney">TransferMoney&lt;/a> bằng cách &lt;code>Mock&lt;/code> kết quả 💪.&lt;/li>
&lt;li>Các lời gọi liên quan tới context như thread context, security context, scope context&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Note:&lt;/strong> Có một bài viết chi tiết của &lt;a href="https://martinfowler.com/articles/mocksArentStubs.html">Martin Fowler ở đây&lt;/a>, có so sánh về &lt;code>Stub&lt;/code> và &lt;code>Mock&lt;/code> và cũng như cung cấp rất nhiều thông tin khác về &lt;code>Test&lt;/code> nên nếu có thời gian các bạn nên đọc qua nhé. Ở đây mình chỉ muốn giới thiệu về &lt;code>Mock&lt;/code> thôi.&lt;/p>
&lt;h3 id="MockAndDependencyInjection">Mock and Dependency Injection&lt;/h3>
&lt;p>Như ví dụ đầu ở &lt;a href="https://trile.dev/post/2020-07-31-use-mock-to-make-unit-test-easy/#WhatsMock">What&amp;rsquo;s Mock&lt;/a> nếu theo cách code truyền thống class xử lý và class truy xuất DB có sự liên hệ chặt chẻ với nhau dẫn đến muốn test ta cần phải setup một DB thật và data trong DB cũng phải thật. May mắn nhờ có &lt;code>IoC và DJ&lt;/code> (xem thêm ở &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">Inversion of Control and Dependency Injection&lt;/a>), ta có thể &lt;code>injection&lt;/code> class truy xuất DB vào class xử lý trong lúc runtime và &lt;code>injection&lt;/code> &lt;code>mock&lt;/code> class truy xuất DB trong trường hợp test. Phần tiếp theo sẽ làm rõ hơn ý mình muốn nói.&lt;/p>
&lt;h3 id="ExampleUnitTestWithMock">Example Unit Test with Mock&lt;/h3>
&lt;p>Ví dụ có yêu cầu sau:&lt;/p>
&lt;blockquote>
&lt;p>Hiển thị full name của những khách hàng mua nhiều hơn N từ Database với N được input vào.&lt;/p>
&lt;/blockquote>
&lt;p>Từ yêu cầu trên mình cần implement &lt;code>CustomerRepository&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">interface&lt;/span> &lt;span class="nc">CustomerRepository&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">CrudRepository&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Customer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Long&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">totalBuyPrice&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Customer&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Và từ các &lt;code>Customer&lt;/code> nhận về mình &lt;code>map()&lt;/code> thành full name như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Component&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CustomerService&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">customerRepository&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">CustomerRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">getFullNameCustomerWithTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">totalBuyPrice&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customerRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">totalBuyPrice&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">${it.firstName}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">${it.lastName}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Và setup &lt;code>mock&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">customerRepository&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">CustomerRepository&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">mockk&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">customerService&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">CustomerService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customerRepository&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@AfterEach&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">tearDown&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">clearMocks&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customerRepository&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Và đây là một trong các &lt;code>test case&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">`test getFullNameCustomerWithTotalBuyPriceGreaterThan return one customer`&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">totalBuyPrice&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">every&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customerRepository&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="n">returns&lt;/span> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">firstName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Tri&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lastName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Le&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assertEquals&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">listOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Tri Le&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customerService&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">getFullNameCustomerWithTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">verify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">exactly&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">customerRepository&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">findByTotalBuyPriceGreaterThan&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">totalBuyPrice&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Một &lt;code>test case&lt;/code> tiêu chuẩn sẽ bao gồm 3 phần:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Setup: từ dòng 5-9, để setup cho mock biết được cần trả về &lt;code>Customer(firstName = &amp;quot;Tri&amp;quot;, lastName = &amp;quot;Le&amp;quot;)&lt;/code> khi &lt;code>customerRepository.findByTotalBuyPriceGreaterThan(3_000)&lt;/code> được gọi&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Assert: từ dòng 11-14 so sánh kết quả mong muốn với kết quả thực tế.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Verify: dòng 16 kiểm tra xem thật sự mock đã được gọi hay không, được gọi với các tham số như thế nào cũng như số lần được gọi. Một số bạn hay bỏ qua bước này nhưng thật ra nó rất &lt;strong>quan trọng&lt;/strong> vì sẽ tránh được các tình huống như code gọi khác số lần mong muốn, hãy tưởng tượng như ở ví dụ bài &lt;a href="post/2020-01-21-clean-code-with-exception">Clean Code with Exception&lt;/a> chuyển lương nhiều lần cho nhân viên thì như thế nào 😓 hoặc lời gọi cần được thực hiện nhưng lại không tham gia vào kết quả trả về 👿.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Note 1:&lt;/strong> Ở đây mình sử dụng &lt;code>Spring JPA&lt;/code> nên không cần phải có &lt;code>implement class&lt;/code>. Các trường hợp khác các bạn cần implement &lt;code>concrete class&lt;/code> và &lt;code>Spring&lt;/code> sẽ tự động biết mà &lt;code>inject&lt;/code> đúng &lt;code>concrete class&lt;/code> khi ứng dụng được khởi chạy. Mình sẽ có có bài chi tiết hơn nha.&lt;/p>
&lt;p>&lt;strong>Note 2:&lt;/strong> Phần code sample mình update vào &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/mock">repo này&lt;/a> nhé.&lt;/p>
&lt;p>&lt;strong>Kết:&lt;/strong> Với sự giúp sức của &lt;code>Mock&lt;/code> việc &lt;code>Unit Test&lt;/code> trở nên đơn giản và đáng tin cậy hơn rất nhiều.&lt;/p>
&lt;p>Cảm ơn các bạn đã đọc tới đây và mong các bạn sẽ thích bài viết này.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h6 id="ReferenceArticles">Reference articles&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren&amp;rsquo;t Stubs - Martin Fowler&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://semaphoreci.com/community/tutorials/stubbing-and-mocking-with-mockito-2-and-junit">Stubbing and Mocking with Mockito and JUnit&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mockk.io/">MockK | mocking library for Kotlin&lt;/a>&lt;/li>
&lt;/ul></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/categories/quality-assurance/">Quality Assurance</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/series/unit-test/">Unit Test</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/unit-test/">unit-test</category><category domain="https://trile.dev/tags/mock/">mock</category></item><item><title>How to Write Testable Code</title><link>https://trile.dev/post/2020-07-28-how-to-write-testable-code/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-28-how-to-write-testable-code/</guid><pubDate>Tue, 28 Jul 2020 08:30:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Ở bài viết &lt;a href="https://trile.dev/post/2020-07-18-introduction-to-unit-test/">Introduction to Unit Test&lt;/a> đã nói lên được sự quan trọng của &lt;code>Unit Test&lt;/code>. Nhưng trước khi áp dụng được &lt;code>Unit Test&lt;/code> vào dự án hiện tại hoặc tương lai thì ta cần phải có một &lt;em>&amp;ldquo;bước đệm&amp;rdquo;&lt;/em> đó học cách viết &lt;code>Testable Code&lt;/code> (là &lt;code>Production Code&lt;/code> cho phép thực hiện &lt;code>Unit Test&lt;/code> dễ dàng). Việc này theo mình là khó khăn và vì thế bài viết này sẽ tổng hợp một số kinh nghiệm của mình để giúp bạn thực hiện việc này dễ dàng hơn.&lt;/p>
&lt;p>Trước khi đọc nội dung bài viết. Mình mong bạn hãy đọc những bài sau để có kiến thức nền cho bài viết này:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/">What are S.O.L.I.D principles?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">Inversion of Control and Dependency Injection&lt;/a>&lt;/li>
&lt;/ul>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video style="height: 200px" autoplay loop muted playsinline src="https://media.giphy.com/media/RLW9YEaSBfBMt79fm4/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h3 id="WriteASimpleUnit">Write a simple Unit&lt;/h3>
&lt;p>Khi ta viết một &lt;code>Unit&lt;/code>&lt;sup id="fnref:1">&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> đơn giản sẽ giúp ích việc &lt;code>Unit Test&lt;/code> trở nên đơn giản vì các yếu tố sau:&lt;/p>
&lt;ul>
&lt;li>Số &lt;code>Test Case&lt;/code> cho &lt;code>Unit&lt;/code> ít hơn.&lt;/li>
&lt;li>Các dependency mà &lt;code>Unit&lt;/code> phụ thuộc cũng ít hơn từ đó việc chuẩn bị hoặc &lt;code>Mock&lt;/code>&lt;sup id="fnref:2">&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> cho các &lt;code>Test Case&lt;/code> cũng trở nên đơn giản.&lt;/li>
&lt;li>Hạn chế việc miss &lt;code>Test Case&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Vậy đối với những yêu cầu phức tạp ta cần làm gì?&lt;/p>
&lt;p>Câu trả lời là tách yêu cầu trên thành các yêu cầu nhỏ hơn và giải quyết từng yêu cầu. Giống việc áp dụng chiến thuật &lt;em>&amp;ldquo;chia để trị&amp;rdquo;&lt;/em> vậy đó ;))&lt;/p>
&lt;h3 id="SeparationBetweenLogicAndPresentation">Separation Between Logic and Presentation&lt;/h3>
&lt;p>Việc tách biệt giữa code xử lý logic và code lưu trữ, hiển thị hoặc call API là việc bắt buộc khi muốn dự án của ta có thể dễ dàng bảo trì và mở rộng về sau. Ý tưởng tách biệt này là ý tưởng chính trong các mô hình &lt;code>MVC&lt;/code>, &lt;code>MVVM&lt;/code>&amp;hellip;
Vì thế mà ngay cả khi chiến lược đảm bảo chất lượng của dự án không yêu cầu &lt;code>Unit Test&lt;/code> thì ta cũng nên thực hiện việc này.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/TIEfjK8GobH9Dk6KRz/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Ngoài ra việc tách biệt này cũng sẽ giúp cho việc đảm bảo &lt;code>Consistency Unit&lt;/code> ở phần sau được thực hiện.&lt;/p>
&lt;h3 id="ConsistencyUnit">Consistency Unit&lt;/h3>
&lt;p>Tính &lt;code>Consistency&lt;/code> ở đây được biểu hiện qua việc với cùng một input thì &lt;code>Unit&lt;/code> luôn trả về &lt;strong>duy nhất&lt;/strong> một output. Việc này giúp việc kiểm tra input và output như mình đề cập ở &lt;a href="https://trile.dev/post/2020-07-18-introduction-to-unit-test#ConceptsInUnitTest">Introduction to Unit Test&lt;/a> có thể được thực hiện.&lt;/p>
&lt;p>Một số trường hợp không thể thực hiện tính &lt;code>Consistency&lt;/code> như:&lt;/p>
&lt;ul>
&lt;li>Hàm liên quan tới &lt;code>random&lt;/code>.&lt;/li>
&lt;li>Các hàm liên quan tới &lt;em>thời gian hiện tại&lt;/em> như tính tuổi hiện tại từ ngày sinh, số ngày chênh lệch ở một thời điểm nào đó so với hiện tại&amp;hellip;&lt;/li>
&lt;li>Các lời gọi tới external system như DB, API, Cache&amp;hellip;&lt;/li>
&lt;li>Các lời gọi liên quan tới context như thread context, security context, scope context&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>Và mình đề xuất 2 cách giải quyết các trường hợp trên như sau:&lt;/p>
&lt;ol>
&lt;li>Tách code logic và code inconsistency kia thành 2 phần riêng biệt. Lúc này input của code logic sẽ là output của code inconsistency. Và ta chỉ &lt;code>Unit Test&lt;/code> phần code logic.&lt;/li>
&lt;li>Tương tự #1 khi tách ra 2 phần riêng biệt. Áp dụng &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">&lt;code>IoC/DI&lt;/code>&lt;/a>, lúc này code logic là &lt;code>Client&lt;/code>, code inconsistency là &lt;code>Service Implement&lt;/code>. Và cũng chỉ cần &lt;code>Unit Test&lt;/code> phần code logic với việc &lt;code>Mock&lt;/code>&lt;sup id="fnref1:2">&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> phần code inconsistency.&lt;/li>
&lt;/ol>
&lt;h3 id="ApplyIoCDI">Apply Ioc/DI&lt;/h3>
&lt;p>Việc áp dụng &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">&lt;code>IoC/DI&lt;/code>&lt;/a> giúp ta có thể dễ dàng &lt;code>Mock&lt;/code>&lt;sup id="fnref2:2">&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> các phụ thuộc cho các &lt;code>class&lt;/code> cần &lt;code>Unit Test&lt;/code> một cách dễ dàng. Ngoài ra việc áp dụng &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">&lt;code>IoC/DI&lt;/code>&lt;/a> cũng sẽ giúp thỏa được nguyên lý &lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#DIP">&lt;code>DIP&lt;/code>&lt;/a> ở phần dưới.&lt;/p>
&lt;h3 id="ApplySOLIDPrinciples">Apply S.O.L.I.D principles&lt;/h3>
&lt;p>Việc áp dụng &lt;code>S.O.L.I.D&lt;/code> đặc biệt có lợi cho việc viết &lt;code>Unit Test&lt;/code> vì:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#SRP">&lt;code>Single responsibility priciple&lt;/code>&lt;/a>: giữ cho các &lt;code>class&lt;/code> chứa các &lt;code>Unit&lt;/code> cần test đơn giản nhất có thể. Từ đó số lượng &lt;code>Test Case&lt;/code> cho &lt;code>class&lt;/code> được giảm xuống.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#OCP">&lt;code>Open/Closed principle&lt;/code>&lt;/a>: Giúp ta không phải viết lại các &lt;code>Test Case&lt;/code> cho phần code cũ khi cần mở rộng tính năng.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#LSP">&lt;code>Liskov substitution principe&lt;/code>&lt;/a>: Đây là nguyên lý khó giải thích được sự liên hệ của nó với &lt;code>Testable Code&lt;/code> :(. Ở đây mình giả sử class A &lt;em>phụ thuộc&lt;/em> class B, ta đã &lt;code>Unit Test&lt;/code> class A và class B rồi. Vậy khi mình viết thêm một class C &lt;em>kế thừa&lt;/em> class B và &lt;em>thay thế&lt;/em> class B bằng class C lúc này ta chỉ cần &lt;code>Unit Test&lt;/code> thêm class C mà không cần phải &lt;code>Unit Test&lt;/code> lại class A nếu thỏa &lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#LSP">&lt;code>LSP&lt;/code>&lt;/a>.
Nếu chương trình thỏa nguyên lý này. Ta sẽ không cần lại &lt;code>Unit Test&lt;/code> những &lt;code>class&lt;/code> đã được&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#ISP">&lt;code>Interface segregation principle&lt;/code>&lt;/a>: nguyên lý này đi kèm với &lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#SRP">&lt;code>SRP&lt;/code>&lt;/a> sẽ giúp đơn giản hóa việc &lt;code>Unit Test&lt;/code> cho các &lt;code>class&lt;/code> implement các &lt;code>interface&lt;/code> thỏa nguyên lý này.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles#DIP">&lt;code>Dependency inversion principle&lt;/code>&lt;/a>: Đây là nguyên lý quan trọng để có thể viết &lt;code>Testable Code&lt;/code> được. Nếu bạn đã áp dụng &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">&lt;code>IoC/DI&lt;/code>&lt;/a> như phần trên thì nguyên lý này cũng tự động thỏa.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Kết:&lt;/strong> Để viết được &lt;code>Testable Code&lt;/code> không phải dễ nhưng khi đã làm được thì xem như bạn có thể bước một chân vào thế giới của các developer &lt;em>&amp;ldquo;xịn&amp;rdquo;&lt;/em> rồi đó. Ngoài ra viết &lt;code>Testable Code&lt;/code> nên thực hiện càng sớm càng tốt vì sẽ tốn rất nhiều thời gian, công sức và rủi ro để chuyển code thường sang &lt;code>Testable Code&lt;/code>.&lt;/p>
&lt;p>Cảm ơn các bạn đã đọc tới đây và mong các bạn sẽ thích bài viết này.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h6 id="ReferenceArticles">Reference articles&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf">Guide To Writing Testable Code&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.gurock.com/highly-testable-code/">4 Properties of Highly Testable Code&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://medium.com/feedzaitech/writing-testable-code-b3201d4538eb">Writing Testable Code&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://medium.com/@jgefroh/why-consistency-is-one-of-the-top-indicators-of-good-code-352ba5d62020">Why consistency is one of the top indicators of good code&lt;/a>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>&lt;code>Unit&lt;/code> ở đây đối với lập trình hướng đối tượng là &lt;code>method&lt;/code>, đối với lập trình hàm là &lt;code>function&lt;/code>, đối với lập trình thủ tục là &lt;code>procedure&lt;/code>.&amp;#160;&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;code>Mock&lt;/code> hiểu đơn giản là cách để giả lập hành vi của các &lt;code>class&lt;/code>, &lt;code>method&lt;/code> bên ngoài &lt;code>Unit&lt;/code> đang được &lt;code>Unit Test&lt;/code>. Còn chi tiết thì ở &lt;a href="https://trile.dev/post/2020-07-31-use-mock-to-make-unit-test-easy/">Use Mock to make Unit Test easy&lt;/a>&amp;#160;&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&amp;#160;&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fnref1:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&amp;#160;&lt;a href="https://trile.dev/post/2020-07-28-how-to-write-testable-code/#fnref2:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/categories/quality-assurance/">Quality Assurance</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/series/unit-test/">Unit Test</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/unit-test/">unit-test</category></item><item><title>What are S.O.L.I.D principles?</title><link>https://trile.dev/post/2020-07-25-what-are-solid-principles/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-25-what-are-solid-principles/</guid><pubDate>Sat, 25 Jul 2020 02:30:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Trên con đường trở thành một developer &lt;em>&amp;ldquo;xịn&amp;rdquo;&lt;/em> thì việc biết và áp dụng thành thạo &lt;code>S.O.L.I.D&lt;/code> là một trong những điều kiện tiên quyết. Nó giúp ta định hình lại tư duy code rất nhiều như việc tổ chắc code, phân chia vai trò và tương tác giữa các module, class, method&amp;hellip; Từ đó giúp code dễ đọc, dễ hiểu, dễ maintaince hơn. Nó giúp ta viết các &lt;code>Testable Code&lt;/code> để thực hiện &lt;a href="https://trile.dev/tags/unit-test/">&lt;code>Unit Code&lt;/code>&lt;/a>. Nó là nguyên lý được áp dụng vào &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">&lt;code>IoC/DI&lt;/code>&lt;/a>. Và còn nhiều ứng dụng khác. Nhưng quan trọng nó sẽ giúp bạn được tăng lương hoặc phỏng vấn tốt hơn đó 😸.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/s.o.l.i.d.jpg" alt="S.O.L.I.D">&lt;/p>
&lt;h3 id="IntroductionToSOLIDPrinciples">Introduction to S.O.L.I.D principles&lt;/h3>
&lt;p>&lt;code>S.O.L.I.D&lt;/code> là tập hợp 5 nguyên lý định hướng thiết kế và code trong &lt;code>lập trình hướng đối tượng (OOP)&lt;/code>. Được đưa ra bởi &lt;code>Bob Martin&lt;/code> (cha đẻ của &lt;em>&amp;ldquo;thánh kinh&amp;rdquo;&lt;/em> &lt;strong>Clean Code&lt;/strong>&lt;sup id="fnref:1">&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>) và &lt;code>Michael Feathers&lt;/code>. 5 nguyên lý trong &lt;code>S.O.L.I.D&lt;/code> bao gồm:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#SRP">Single responsibility priciple&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#OCP">Open/Closed principle&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#LSP">Liskov substitution principe&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#ISP">Interface segregation principle&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#DIP">Dependency inversion principle&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>→&lt;/strong> &lt;code>S.O.L.I.D&lt;/code> là cách chơi chữ từ 5 chữ cái đầu cửa các nguyên lý, cũng khá thú vị phải không ;)).&lt;/p>
&lt;h3 id="SRP">Single responsibility priciple&lt;/h3>
&lt;blockquote>
&lt;p>A class should only have a single responsibility, that is, only changes to one part of the software&amp;rsquo;s specification should be able to affect the specification of the class.&lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/SOLID">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Nguyên tắt này tuyên bố một &lt;code>class&lt;/code> chỉ nên có một trách nhiệm và việc thay đổi nó cũng chỉ vì đúng trách nhiệm đó thôi. Nguyên lý này sẽ rất hữu dụng đối với những dự án lớn nơi mà chỉ cần một thay đổi nhỏ có thể ảnh hưởng tới toàn bộ chương trình.&lt;/p>
&lt;h3 id="OCP">Open/Closed principle&lt;/h3>
&lt;blockquote>
&lt;p>Software entities &amp;hellip; should be open for extension, but closed for modification.&lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/SOLID">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Nguyên lý này khuyên chúng ta viết thêm một &lt;code>class&lt;/code> mới kế thừa từ &lt;code>class&lt;/code> cũ để mở rộng tính năng thay vì sửa &lt;code>class&lt;/code> cũ. Nguyên lý này rất hữu ích với những dự án cũ khi mà việc thay đổi có thể ảnh hưởng tới những chức năng hiện tại.&lt;/p>
&lt;h3 id="LSP">Liskov substitution principe&lt;/h3>
&lt;blockquote>
&lt;p>Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.&lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/SOLID">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Các &lt;code>object&lt;/code> của class con có thể &lt;em>thay thế&lt;/em> cho class cha mà không làm thay đổi tính đúng đắng của chương trình. Nguyên lý này giúp đảm bảo tính đúng đắn và ổn định cho chương trình. Đây là nguyên lý rất dễ bị vi phạm nếu developer không chú ý và có thể dẫn đến những hậu quả to lớn.&lt;/p>
&lt;h3 id="ISP">Interface segregation principle&lt;/h3>
&lt;blockquote>
&lt;p>Many client-specific interfaces are better than one general-purpose interface.&lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/SOLID">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Nguyên lý này khá đơn giản khi yêu cầu ta nên chia nhỏ các &lt;code>interface&lt;/code> ra sẽ tốt hơn một &lt;code>interface&lt;/code> có nhiều mục đích. Lý do của việc này nhằm tránh dư thừa những method cần phải implement khi kế thừa &lt;code>interface&lt;/code> nhiều mục đích ở trên.&lt;/p>
&lt;h3 id="DIP">Dependency inversion principle&lt;/h3>
&lt;blockquote>
&lt;p>One should &amp;ldquo;depend upon abstractions, [not] concretions&amp;rdquo;.&lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/SOLID">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/l2Sq6SpDtVi02j9Cw/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>một định nghĩa dễ hiểu hơn ;))&lt;/p>
&lt;blockquote>
&lt;p>Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.&lt;/p>
&lt;/blockquote>
&lt;p>Chắc đọc tới đây vẫn chưa hiểu đâu. Đây là nguyên lý khó hiểu nhất vì cũng trừu tượng nhất mà;)).&lt;/p>
&lt;p>Mình lấy ví dụ việc &lt;em>lái xe đạp&lt;/em> và &lt;em>lái máy bay&lt;/em> (ý mình là nghĩa đen nhé 😽). Về cơ bản hai hành động này rất khác nhau. Nhưng nếu ta &lt;em>trừu tượng hóa&lt;/em> thành các hành động đơn giản hơn như: &lt;em>bẻ lái&lt;/em>, &lt;em>tăng/giảm tốc&lt;/em>, &lt;em>thắng&lt;/em> thì lúc này 2 hành động trên là tương tự nhau và cụ thể hóa của &lt;em>bẻ lái&lt;/em>, &lt;em>tăng/giảm tốc&lt;/em>, &lt;em>thắng&lt;/em> là khác nhau.&lt;/p>
&lt;p>Hãy xem thêm bài &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/">Inversion of Control and Dependency Injection&lt;/a> để thấy được &lt;code>IOC/DI&lt;/code> cũng là một phần của việc áp dụng nguyên lý này nha các bạn.&lt;/p>
&lt;p>&lt;strong>Kết:&lt;/strong> &lt;code>S.O.L.I.D&lt;/code> là khái niệm khó, việc hiểu nó cũng là một vấn đề với người mới nhưng &lt;code>S.O.L.I.D&lt;/code> chỉ thật sự có ý nghĩa nếu được áp dụng vào dự án. Và tin mình đi một khi đã áp dụng được &lt;code>S.O.L.I.D&lt;/code> vào dự án thì công việc code và maintaince và test sẽ trở nên dễ dàng. Bài viết này chỉ dừng lại ở mức khái niệm. Việc áp nó như thể nào sẽ có một loạt bài nói riêng nhé.&lt;/p>
&lt;p>Cảm ơn các bạn đã đọc tới đây và mong các bạn sẽ thích bài viết này.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h6 id="ReferenceArticles">Reference articles&lt;/h6>
&lt;ul>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/SOLID">SOLID - Wikipedia&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://toidicodedao.com/2015/03/24/solid-la-gi-ap-dung-cac-nguyen-ly-solid-de-tro-thanh-lap-trinh-vien-code-cung/">SOLID LÀ GÌ – ÁP DỤNG CÁC NGUYÊN LÝ SOLID ĐỂ TRỞ THÀNH LẬP TRÌNH VIÊN CODE “CỨNG”&lt;/a>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Clean Code: A Handbook of Agile Software Craftsmanship là tên của một quyển sách được viết bởi Robert Martin, được xem là sách &lt;em>&amp;ldquo;gối đầu giường&amp;rdquo;&lt;/em> của mọi developer. Giới thiệu những cách giúp code dễ đọc, dễ hiểu, dễ maintaince hơn.&amp;#160;&lt;a href="https://trile.dev/post/2020-07-25-what-are-solid-principles/#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/tags/s.o.l.i.d/">s.o.l.i.d</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/unit-test/">unit-test</category><category domain="https://trile.dev/tags/should/">should</category></item><item><title>Introduction to Unit Test</title><link>https://trile.dev/post/2020-07-18-introduction-to-unit-test/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-18-introduction-to-unit-test/</guid><pubDate>Sat, 18 Jul 2020 02:30:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Vào năm 2015 có một sự kiện làm thay đổi suy nghĩ của mình về &lt;code>Testing&lt;/code> trong quy trình phát triển phần mềm. Đây là lần đầu tiên mình phải viết report &lt;code>5 whys 9 steps&lt;/code>. Nguyên nhân chính của vấn đề này là mình xem nhẹ &lt;code>Unit Test&lt;/code> và hậu quả thì khá nặng nề. Vì sao thì các bạn xem tiếp bài viết nhé ;)).&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/unit-test.png" alt="UnitTest">&lt;/p>
&lt;p>Trước đó, lúc học đại học thì mình đã biết khái niệm &lt;code>Black Box Test&lt;/code> và &lt;code>White Box Test&lt;/code>. Khái niệm &lt;code>Unit Test&lt;/code> lần đầu mình được biết vào năm 2013 khi mình còn ở &lt;a href="http://www.globalcybersoft.com">Global CyberSoft&lt;/a>. Lúc này leader cũng chỉ xem nó mang tính &lt;em>&amp;ldquo;report&amp;rdquo;&lt;/em>, các &lt;em>&amp;ldquo;chốt chặn&amp;rdquo;&lt;/em> chất lượng cho dự án hầu hết ở bước &lt;code>Code Review&lt;/code> và &lt;code>Test&lt;/code>. May mắn thay leader và QC team mình chuyên môn rất tốt nên chất lượng dự án vẫn ở mức tốt.&lt;/p>
&lt;p>Vào năm 2015 mình chuyển qua làm việc tại Mulodo. Mình và một em sinh năm 91 tiếp nhận 2 dự án của 2 bạn chuẩn bị rời công ty. Thời gian gấp rút nhưng tài liệu thiếu, tinh thần muốn rời đi làm cho quá trình transfer dự án không được tốt. Kết quả bọn mình đã phải nhận một &lt;em>&amp;ldquo;bug siêu khủng long&amp;rdquo;&lt;/em> ngay lần change request thứ 2. Nguyên nhân là do sửa lại một hàm &lt;code>utility&lt;/code> và vì hàm này được sử dụng ở rất nhiều function nên lỗi này rất nghiêm trọng. Lúc này mình vẫn nghĩ nguyên nhân lỗi là do &lt;em>&amp;ldquo;miss knowlead&amp;rdquo;&lt;/em> hoàn toàn có thể phát hiện ở bước &lt;code>Code Review&lt;/code>. Nhưng sau khi trúng &lt;em>&amp;ldquo;thông não chi thuật&amp;rdquo;&lt;/em> của Manager thì mình nhận ra lỗi này hoàn toàn có thể tránh được nếu áp dụng &lt;code>Unit Test&lt;/code> đúng.&lt;/p>
&lt;p>Vậy &lt;code>Unit Test&lt;/code> là gì và vì sao nó lại cần thiết?&lt;/p>
&lt;h3 id="WhatIsUnitTest">What is Unit Test?&lt;/h3>
&lt;p>&lt;code>Unit Test&lt;/code> là một bước trong quy trình phát triển phần mềm. Nó được nên được bắt đầu ngay sau &lt;code>Functional Design&lt;/code>, trước &lt;code>Implement&lt;/code> và kết thúc sau khi &lt;code>Implement&lt;/code> xong. Nhằm mục đích đảm bảo phần code được implement đúng với thiết kế. &lt;code>Unit Test&lt;/code> được thực hiện bởi lập trình viên và được xem là &lt;code>White Box Test&lt;/code>.&lt;/p>
&lt;p>&lt;code>Unit&lt;/code> ở đây đối với lập trình hướng đối tượng là &lt;code>method&lt;/code>, đối với lập trình hàm là &lt;code>function&lt;/code>, đối với lập trình thủ tục là &lt;code>procedure&lt;/code>. Khi này lập trình viên sẽ liệt kê ra tất cả các trường hợp logic mà &lt;code>Unit&lt;/code> đó sẽ chạy qua, từ đó sẽ tạo ra một bộ các input và output (bao gồm cả kết quả mong muốn và lỗi mong muốn) tương ứng cho các trường hợp đó. Framework &lt;code>Unit Test&lt;/code> sẽ hỗ trợ xác nhận lại input và output cho từng trường hợp và báo cáo kết quả cuối cùng.&lt;/p>
&lt;h3 id="WhyDoIHaveToWriteUnitTest">Why do I have to write Unit Test?&lt;/h3>
&lt;ul>
&lt;li>Đảm bảo &lt;code>Unit&lt;/code> chạy đúng với thiết kế. Sự đảm bảo này lại càng quan trọng trong trường hợp update lại logic của &lt;code>Unit&lt;/code>. Giá như mình biết cái này sớm hơn và &lt;em>&amp;ldquo;người trước&amp;rdquo;&lt;/em> viết &lt;code>Unit Test&lt;/code> nghiêm chỉnh hơn thì đã không dính lỗi ở ở trên :((.&lt;/li>
&lt;li>Hiễu rõ hơn về yêu cầu và định hướng &lt;code>Implement&lt;/code> trước. Như mình đã nói, &lt;code>Unit Test&lt;/code> phải bắt đầu trước &lt;code>Implement&lt;/code>, khi này ta sẽ liệt kê ra tất cả các trường hợp sẽ xảy ra và chốt được bộ input và output cho các trường hợp đó, giống như việc muốn đi đâu thì cần biết điểm đến vậy đó ;)).&lt;/li>
&lt;li>Phát hiện lỗi sớm &lt;strong>→&lt;/strong> &lt;strong>tiết kiệm chi phí và thời gian&lt;/strong>.&lt;/li>
&lt;li>Khi viết &lt;code>Unit Test&lt;/code> developer cần phải xem lại code của chính mình. Đây cũng có thể xem là một hình thức &lt;em>&amp;ldquo;ép buộc&amp;rdquo;&lt;/em> &lt;strong>tự review&lt;/strong> ;)).&lt;/li>
&lt;li>Giảm tải cho &lt;code>Code Review&lt;/code>. Đối với ai đang là lead hoặc phải peer review thì chắc chắn muốn người implement code thực hiện &lt;code>Unit Test&lt;/code>.&lt;/li>
&lt;li>Phát hiện những lỗi tiềm ẩn mà &lt;code>Black Box Test&lt;/code> không thể phát hiện.&lt;/li>
&lt;li>Là một phần không thể thiếu trong việc triển khai &lt;code>CI/CD&lt;/code>.&lt;/li>
&lt;/ul>
&lt;h3 id="ConceptsInUnitTest">Concepts in Unit Test?&lt;/h3>
&lt;ul>
&lt;li>&lt;code>Test Case&lt;/code>: là một trường hợp logic mà &lt;code>Unit&lt;/code> cần test có thể xảy ra trong quá trình chạy. Với mỗi &lt;code>Test Case&lt;/code> ta cần phải xác định được một bộ input và output tương ứng.&lt;/li>
&lt;li>&lt;code>Assertion&lt;/code>: Là một phát biểu mô tả các công việc kiểm tra output cần tiến hành. Như trong &lt;a href="https://junit.org/">&lt;code>JUnit&lt;/code>&lt;/a> là các hàm: &lt;code>assertEquals&lt;/code>, &lt;code>assertThrows&lt;/code>, &lt;code>assertArrayEquals&lt;/code>, &lt;code>assertNotNull&lt;/code>, &lt;code>assertNull&lt;/code>&amp;hellip;&lt;/li>
&lt;li>&lt;code>Test Suite&lt;/code>: là tập hợp các &lt;code>Test Case&lt;/code>. Các &lt;code>Test Suite&lt;/code> có thể phân loại dựa vào module, package, class hoặc thậm chí là &lt;code>Unit&lt;/code> tùy thuộc vào số lượng &lt;code>Test Case&lt;/code>, độ phức tạp của &lt;code>Unit&lt;/code> hoặc chiến lược của người viết &lt;code>Unit Test&lt;/code>.&lt;/li>
&lt;li>&lt;code>Production Code&lt;/code>: Là phần code chính sẽ được chạy khi deploy lên production.&lt;/li>
&lt;li>&lt;code>Test Code&lt;/code>: Là phần code để thực thi &lt;code>Unit Test&lt;/code>, nó bao gồm tất cả các &lt;code>Test Suite&lt;/code>. Phần code này sẽ được chạy trong quá trình build và không include vào &lt;code>Production Code&lt;/code>. Ngoài ra lập trình viên cũng nên chạy ở local trước khi &lt;code>Merge (Pull) Request&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Kết:&lt;/strong> Mong sau bài viết này bạn sẽ thấy được sự quan trọng của &lt;code>Unit Test&lt;/code>. Kiến thức về &lt;code>Unit Test&lt;/code> thì rất nhiều và mình sẽ tiếp tục viết nhiều nâng cao hơn về chủ đề &lt;em>thú vị&lt;/em> này. Kết thúc bài viết mình xin trích một câu nói từ Manager cũ của mình người đã giúp mình &lt;em>&amp;ldquo;thông não&amp;rdquo;&lt;/em> ;)).&lt;/p>
&lt;blockquote>
&lt;p>Unit Test không phải là trách nhiệm của lập trình viên mà là quyền lợi. Nó bảo vệ chúng ta khỏi những lỗi tiềm ẩn. Vì thế hãy viết nó &amp;ldquo;bằng cả trái tim&amp;rdquo;.&lt;br>
— &lt;cite>Tài Nguyễn&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Cảm ơn các bạn đã đọc tới đây.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/categories/quality-assurance/">Quality Assurance</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/series/unit-test/">Unit Test</category><category domain="https://trile.dev/tags/unit-test/">unit-test</category></item><item><title>Inversion of Control and Dependency Injection</title><link>https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/</guid><pubDate>Sat, 11 Jul 2020 02:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Vào năm 2012, khi mình vừa mới gia nhập gia đình &lt;a href="http://www.globalcybersoft.com">Global CyberSoft&lt;/a>, bước chân vào thế giới lập trình với nhiều bỡ ngỡ 😅 thì 2 khái niệm &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#WhatIsInversionOfControl">&lt;code>Inversion of Control (IoC)&lt;/code>&lt;/a> và &lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#WhatIsDependencyInjection">&lt;code>Dependency Injection (DI)&lt;/code>&lt;/a> là khó nhằn nhất với mình nhưng nó lại là nền tảng cho những ứng dụng sau này. Cùng mình tìm hiểu vì sao nó lại quan trọng như thế nhé.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/dependency-injection.webp" alt="Dependency Injection">&lt;/p>
&lt;p>Nội dung bài viết:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#DependencyProblemInOOP">Dependency problem in OOP?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#WhatIsInversionOfControl">What is Inversion of Control?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#WhatIsDependencyInjection">What is Dependency Injection?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-11-inversion-of-control-and-dependency-injection/#ImplementSalaryTransferByDependencyInjection">Implement Salary Transfer by Dependency Injection&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="DependencyProblemInOOP">1. Dependency problem in OOP&lt;/h3>
&lt;p>Trong &lt;code>lập trình hướng đối tượng (OOP)&lt;/code> có một vấn đề với các chương trình lớn là sự phụ thuộc của các &lt;code>class&lt;/code> với nhau trong chương trình. Việc phụ thuộc này làm chương trình rất khó thay đổi, mở rộng cũng như thực hiện &lt;code>Unit Test&lt;/code> là không thể với những &lt;code>class&lt;/code> bị phụ thuộc vào các &lt;code>class&lt;/code> khác.&lt;/p>
&lt;p>Khó hiểu quá!!! Mình sẽ lấy ví dụ ở bài &lt;a href="https://trile.dev/post/2020-03-15-custom-exception">Custom Exception&lt;/a> để giải thích cho các bạn dễ hiểu hơn nha.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/3oEjI5VtIhHvK37WYo/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Dưới đây là &lt;code>class diagram&lt;/code> của ví dụ:
&lt;img src="https://trile.dev/diagram/salary-transfer.svg" alt="Transfer Transfer class diagram">
và giả sử ngoài chức năng &lt;code>Money Transfer&lt;/code> thì còn có các chức năng khác như: &lt;code>Money Topup&lt;/code>, &lt;code>Money Withdraw&lt;/code>, &lt;code>Money Exchange Rates&lt;/code>&amp;hellip; phụ thuộc vào 2 class &lt;code>VietcomBank&lt;/code> và &lt;code>VietinBank&lt;/code>. Nếu có yêu cầu thay đổi &lt;code>VietcomBank&lt;/code> thành một ngân hàng khác thì ta cần phải sửa code lại tất cả các class &lt;code>Money Transfer&lt;/code> &lt;code>Money Topup&lt;/code>, &lt;code>Money Withdraw&lt;/code>, &lt;code>Money Exchange Rates&lt;/code>&amp;hellip; Hãy tưởng tượng nếu chương trình ta có hàng chục, hàng trăm class. Các phụ thuộc có thể là hàng trăm thì chỉ với &lt;em>&amp;ldquo;một yêu cầu nhỏ&amp;rdquo;&lt;/em> cũng dẫn tới việc thay đổi cấu trúc chương trình rất lớn và tiềm ẩn nhiều rủi ro.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/ZEICv01RJtDh5P8dJO/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Để giải quyết vấn đề trên người ta đã đưa ra một &lt;code>nguyên tắc lập trình&lt;/code> là &lt;code>Inversion of Control&lt;/code>&lt;/p>
&lt;h3 id="WhatIsInversionOfControl">2. What is Inversion of Control?&lt;/h3>
&lt;blockquote>
&lt;p>In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-written portions of a computer program receive the flow of control from a generic framework. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom, or task-specific, code. &lt;br>
— &lt;cite>&lt;a href="https://en.wikipedia.org/wiki/Inversion_of_control">Wikipedia&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Choáng rồi phải không ;))&lt;/p>
&lt;p>Đấy là định nghĩa của các anh Tây. Còn với mình thì &lt;code>IoC&lt;/code> có thể hiểu như một ý tưởng &lt;em>&amp;ldquo;đảo ngược&amp;rdquo;&lt;/em> lại cách truyền thống khi mà việc khai báo và khởi tạo các phụ thuộc ở các &lt;code>class&lt;/code> được chuyển sang cho &lt;code>framework&lt;/code>. Nói cách khác chỉ có một nơi làm nhiệm vụ quản lý các phụ thuộc là &lt;code>framework&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://trile.dev/diagram/ioc.svg" alt="IoC explain">&lt;/p>
&lt;p>Các &lt;strong>ưu điểm&lt;/strong> của &lt;code>IoC&lt;/code>:&lt;/p>
&lt;ul>
&lt;li>Tách việc thực thi nhiệm vụ cụ thể ra khỏi code điều phối. Như ở ví dụ &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/custom-exception">Money Transfer&lt;/a> thì class &lt;code>Money Transfer&lt;/code> không cần quan tâm 2 class &lt;code>VietcomBank&lt;/code> và &lt;code>VietinBank&lt;/code> làm gì.&lt;/li>
&lt;li>Dễ dàng chuyển đổi các phụ thuộc. Như ta có thể khai báo thay thế &lt;code>VietcomBank&lt;/code> sang &lt;code>TechcomBank&lt;/code> (mới) một cách dễ dàng.&lt;/li>
&lt;li>Module hóa chương trình.&lt;/li>
&lt;li>Dễ dàng tạo ra các &lt;code>Testable Class&lt;/code>. Mình sẽ giải thích việc này sau ở bài về &lt;code>Unit Test&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Nhưng cũng có kèm những &lt;strong>khuyết điểm&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Phụ thuộc vào &lt;code>framework&lt;/code>.&lt;/li>
&lt;li>Khó hiểu đối với người mới.&lt;/li>
&lt;li>Những lỗi khi khai báo phụ thuộc chuyển từ &lt;code>compile time&lt;/code> sang &lt;code>runtime&lt;/code>.&lt;/li>
&lt;li>Chương trình khởi động chậm hơn do cần đọc config, khởi tạo các phụ thuộc.&lt;/li>
&lt;/ul>
&lt;h3 id="WhatIsDependencyInjection">3. What is Dependency Injection?&lt;/h3>
&lt;p>&lt;code>Ioc&lt;/code> là một &lt;em>ý tưởng&lt;/em> hay &lt;em>nguyên tắt&lt;/em> thôi. Còn việc hiện thực nó thì có nhiều có nhiều cách. Trong số đó cách nổi trội nhất là &lt;code>Dependency Injection (DI)&lt;/code>. Vậy &lt;code>DI&lt;/code> hiện thực &lt;code>IoC&lt;/code> như thế nào?&lt;/p>
&lt;p>Để hiện thực được &lt;code>IoC&lt;/code> thì bên trong &lt;code>DI&lt;/code> sẽ có các thành phần sau:&lt;/p>
&lt;ul>
&lt;li>Client: là các &lt;code>class&lt;/code> có phụ thuộc.&lt;/li>
&lt;li>Service: là các &lt;code>interface&lt;/code> hoặc &lt;code>abstract class&lt;/code> bị các &lt;code>Client&lt;/code> phụ thuộc.&lt;/li>
&lt;li>Service Implement: là các &lt;code>implement class&lt;/code> cụ thể của &lt;code>Service&lt;/code>.&lt;/li>
&lt;li>Injector: là đối tượng chị trách nhiệm khởi tạo các &lt;code>Client&lt;/code> và &lt;code>Service Implement&lt;/code>, sau đó dựa vào các khai báo phụ thuộc ở &lt;code>Client&lt;/code> và mapping giữa &lt;code>Service&lt;/code> và &lt;code>Service Implement&lt;/code> sẽ &lt;code>inject&lt;/code> các &lt;code>Service Implement&lt;/code> vào trong các &lt;code>Client&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Và các bước mà &lt;code>DI&lt;/code> sẽ thực hiện:&lt;/p>
&lt;p>&lt;img src="https://trile.dev/diagram/how-to-di-work.svg" alt="How to Dependency Injection work?">&lt;/p>
&lt;h3 id="ImplementSalaryTransferByDependencyInjection">4. Implement Salary Transfer by Dependency Injection&lt;/h3>
&lt;p>Mình đã convert tất cả code ví dụ &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/custom-exception">Money Transfer&lt;/a> từ &lt;code>Java&lt;/code> sang &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>. Đã hứa có bài hướng dẫn chuyển nhưng tới giờ vẫn chưa làm được 😂.&lt;/p>
&lt;p>Về &lt;code>DI framework&lt;/code> thì mình chọn &lt;a href="https://spring.io">&lt;code>Srping&lt;/code>&lt;/a> nhé. Đơn giản vì nó hiện là &lt;strong>framework Java mạnh mẽ nhất&lt;/strong>. Sau đó update lại file &lt;code>build.gradle.kts&lt;/code> giống ở &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/blob/master/ioc-di/build.gradle.kts">đây&lt;/a>. Mình sẽ tập trung vào &lt;code>Spring IoC&lt;/code> nên các config khác xin phép bỏ qua.&lt;/p>
&lt;p>Vì các class &lt;code>SalaryTransfer&lt;/code>, &lt;code>MoneyTransfer&lt;/code> và &lt;code>SalaryCalculator&lt;/code> là &lt;code>Service Implement&lt;/code> của lần lượt các class &lt;code>IocdiApplication&lt;/code>, &lt;code>SalaryTransfer&lt;/code> nên mình sẽ thêm anotation &lt;code>@Component&lt;/code>. Lưu ý mình không khai báo &lt;code>Service&lt;/code> vì cảm thấy không cần thiết lắm.&lt;/p>
&lt;p>Hai class &lt;code>VietcomBank&lt;/code> và &lt;code>VietinBank&lt;/code> mình không dùng cách thêm anotation &lt;code>@Component&lt;/code> vì lúc này có cùng 2 class cùng implement interface &lt;code>Bank&lt;/code> và &lt;code>Spring Injector&lt;/code> sẽ không biết chọn class nào để inject vào &lt;code>Client&lt;/code> của hai class trên là &lt;code>MoneyTransfer&lt;/code>. Vì thế mình khai báo như sau ở class &lt;code>IocdiApplication&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@SpringBootApplication&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IocdiApplication&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Bean&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">primaryBank&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">VietcomBank&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Bean&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">secondaryBank&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">VietinBank&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>khi tham chiếu với contructor của &lt;code>MoneyTransfer&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Component&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">MoneyTransfer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">primaryBank&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Bank&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">secondaryBank&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Bank&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>thì &lt;code>Spring Injector&lt;/code> sẽ hiểu được sẽ inject &lt;code>VietcomBank&lt;/code> vào &lt;code>primaryBank&lt;/code> và &lt;code>VietinBank&lt;/code> vào &lt;code>secondaryBank&lt;/code>. Quá đơn giản phải không ;))&lt;/p>
&lt;p>Ta chạy command sau để build&lt;/p>
&lt;pre tabindex="0">&lt;code>./gradlew clean build
&lt;/code>&lt;/pre>&lt;p>và test thử:&lt;/p>
&lt;pre tabindex="0">&lt;code>java -jar build/libs/*.jar 11 1000000 EM1
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>Transfer 11000000 to EM1
VCB only support transfer amount less than 10M
Retry with VTB
VTB transfer success
Transfer Salary success
&lt;/code>&lt;/pre>&lt;p>Bây giờ ta hãy thử hoán đổi vị trí &lt;code>VietcomBank&lt;/code> vào &lt;code>secondaryBank&lt;/code> và &lt;code>VietinBank&lt;/code> vào &lt;code>primaryBank&lt;/code> như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@SpringBootApplication&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IocdiApplication&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Bean&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">primaryBank&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">VietinBank&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Bean&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">secondaryBank&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">VietcomBank&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Build và chạy lại thì kết quả là:&lt;/p>
&lt;pre tabindex="0">&lt;code>Transfer 11000000 to EM1
VTB transfer success
Transfer Salary success
&lt;/code>&lt;/pre>&lt;p>Như vậy ta chỉ cần đổi phần config ở class &lt;code>IocdiApplication&lt;/code> là logic của chương trình có thể được thay đổi.&lt;/p>
&lt;p>&lt;strong>Kết:&lt;/strong> &lt;code>IoC&lt;/code> và &lt;code>DI&lt;/code> có thể xem khái niệm khó hiểu đối với người mới nhưng mong với bài này bạn sẽ hiểu nó hơn. Có rất nhiều framework mạnh mẽ sử dụng hai khái niệm trên như một phần không thể tách rời. Vì thế đây là đòn bẩy để giúp các bạn học lập trình nhanh hơn. Ngoài ra với các chương trình lớn, bạn sẽ không thể viết được các &lt;code>Testable Class&lt;/code> là điều kiện tiên quyết để áp dụng &lt;code>Unit Test&lt;/code> mà sau này sẽ cứu mạng bạn rất nhiều lần đó ;)). Tin mình đi! Thời gian bạn bỏ ra để học &lt;code>IoC&lt;/code> và &lt;code>DI&lt;/code> là cực kỳ xứng đáng đấy 💪.&lt;/p>
&lt;p>Phần code sample mình update vào &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/ioc-di">repo này&lt;/a> nhé. Cảm ơn các bạn đã đọc tới đây.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p></description><category domain="https://trile.dev/categories/software-development/">Software Development</category><category domain="https://trile.dev/series/become-professional-developer/">Become Professional Developer</category><category domain="https://trile.dev/tags/inversion-of-control/">inversion-of-control</category><category domain="https://trile.dev/tags/dependency-injection/">dependency-injection</category><category domain="https://trile.dev/tags/spring/">spring</category></item><item><title>Resolve Race Condition problems with Map-Reduce and Coroutines</title><link>https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/</link><guid isPermaLink="true">https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/</guid><pubDate>Sat, 04 Jul 2020 02:30:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Tiếp sau bài &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts">Kotlin Coroutines Basic Concepts&lt;/a>. Bài này mình sẽ tận dụng những kiến thức trên để giải quyết một vấn đề trong &lt;code>Concurrent&lt;/code> đó là &lt;code>Race Condition&lt;/code> bằng ý tưởng &lt;code>Map-Reduce&lt;/code>. Bài này khá ngắn nhưng lại đề cập được 2 chủ đề rất hay là &lt;code>Race Condition&lt;/code> và &lt;code>Map-Reduce&lt;/code> nên các bạn hãy đọc tới cuối bài nhé ;))&lt;/p>
&lt;p>Nội dung bài viết:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#WhatIsRaceCondition">What is Race Condition?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#HowToResolveRaceCondition">How to resolve Race Condition?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#WhatIsMapReduce">What is Map-Reduce?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#ResolveRaceConditionWithMapReduce">Resolve Race Condition with Map-Reduce&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="WhatIsRaceCondition">1. What is Race Condition?&lt;/h3>
&lt;p>Hãy nhìn video sau:
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/21PV0Su6USswD76iLv/giphy.mp4">&lt;/video>
&lt;/div>
và tưởng tượng các chú chó là &lt;code>thread&lt;/code> còn trái banh là &lt;code>resource&lt;/code> ;))&lt;/p>
&lt;p>Không cần giải thích nhiều thì chắc các bạn cũng thấy cũng thấy &lt;code>resource&lt;/code> sẽ có thể không chính xác hoặc toàn vẹn nếu có nhiều &lt;code>thread&lt;/code> cùng tranh chấp trong một thời điểm.&lt;/p>
&lt;h3 id="HowToResolveRaceCondition">2. How to resolve Race Condition?&lt;/h3>
&lt;p>Nguyên nhân của &lt;code>Race Condition&lt;/code> là do &lt;em>tranh chấp&lt;/em> &lt;code>resource&lt;/code>. Vậy chỉ cần giải quyết được vấn đề này sẽ giải quyết được &lt;code>Race Condition&lt;/code>, và ta có 2 &amp;ldquo;trường phái&amp;rdquo; là:&lt;/p>
&lt;h6 id="UseSynchronizationsOrAtomicOperations">1. Sử dụng &lt;strong>Synchronizations&lt;/strong>&lt;sup id="fnref:1">&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> hoặc &lt;strong>Atomic Operations&lt;/strong>&lt;sup id="fnref:2">&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/h6>
&lt;h6 id="AvoidShareState">2. Tránh chia sẻ trạng thái&lt;/h6>
&lt;p>Quay lại ví dụ về các chú chó và trái banh thì 2 cách giải quyết sẽ như sau:&lt;/p>
&lt;ol>
&lt;li>Sẽ cũng chỉ có 1 trái banh và các chú cho phải đợi tới lượt mình chơi - các chú chó chắc sẽ không được vui 😂.&lt;/li>
&lt;li>Sẽ có nhiều trái banh cho các chú chó và chắc chắn chú chó nào cũng vui 💪.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>→&lt;/strong> vậy chỉ cần phụ thuộc vào điều kiện anh chủ ;))&lt;/p>
&lt;p>Trong thực tế, thì trước đây khi phần cứng chưa phát triển, các hệ thống máy tính chỉ có một core, bộ nhớ RAM đắt đỏ thì &lt;strong>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#UseSynchronizationsOrAtomicOperations">#1&lt;/a>&lt;/strong> là sự lựa chọn tốt hơn nhưng tới thời điểm hiện tại mình tin rằng &lt;strong>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#AvoidShareState">#2&lt;/a>&lt;/strong> là giải pháp tối ưu hơn.&lt;/p>
&lt;p>Tuy nhiên vẫn có một số trường hợp &lt;em>bắt buộc&lt;/em> phải dùng &lt;strong>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#UseSynchronizationsOrAtomicOperations">#1&lt;/a>&lt;/strong> như: số dư tài khoản ngân hàng, chỉ số chứng khoán&amp;hellip;&lt;/p>
&lt;h3 id="WhatIsMapReduce">3. What is Map-Reduce?&lt;/h3>
&lt;p>Đọc tới đây chắc bạn cũng đưa ra nhận định &lt;strong>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#AvoidShareState">#2&lt;/a>&lt;/strong> là lựa chọn tối ưu để giải quyết &lt;code>Race Condition&lt;/code> trong thời điểm hiện tại. Nhưng làm thế nào để hiện thực &lt;strong>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#AvoidShareState">#2&lt;/a>&lt;/strong>? Một trong những cách hiện thực là &lt;code>Map-Reduce&lt;/code>. Vậy &lt;code>Map-Reduce&lt;/code> là gì?&lt;/p>
&lt;p>&lt;strong>Map-Reduce&lt;/strong> lần đầu tiên được giới thiệu bởi Jeffery Dean và Sanjay Ghemawat lúc đó đang làm việc ở Google vào năm 2004,
và là ý tưởng cơ bản để hiện thực &lt;a href="https://hadoop.apache.org">Hadoop&lt;/a>. Về cơ bản, đây là cách thực hiện của tinh thần &lt;em>chia để trị&lt;/em>. Khi thực thi, sẽ có 2 bước là:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Map&lt;/strong>: chia dữ liệu cần xử lý thần các phần nhỏ và xử lý các phần nhỏ đó.&lt;/li>
&lt;li>&lt;strong>Reduce&lt;/strong>: tổng hợp dữ liệu đã xử lý để cho ra kết quả cuối cùng.&lt;/li>
&lt;/ol>
&lt;p>Lý thuyết hơi khó hiểu nên bạn xem hình này nha:&lt;/p>
&lt;p>&lt;img src="https://www.todaysoftmag.com/images/articles/tsm33/large/a11.png" alt="Word Count">&lt;/p>
&lt;p>đây ví dụ &amp;ldquo;Word Count&amp;rdquo; trong bài &lt;a href="https://www.todaysoftmag.com/article/1358/hadoop-mapreduce-deep-diving-and-tuning">Hadoop MapReduce deep diving and tuning
&lt;/a>. Nhiệm vụ là cần đếm số lần xuất hiện của một từ trong phần Input. Với bước &lt;strong>Map&lt;/strong> được chia thành 2 bước nhỏ: Splitting và Mapping, &lt;strong>Reduce&lt;/strong> được chia thành 2 bước nhỏ: Shuffling và Reducing.&lt;/p>
&lt;h3 id="ResolveRaceConditionWithMapReduce">Resolve Race Condition with Map-Reduce&lt;/h3>
&lt;p>Đây là phần chính của bài viết. Mình sẽ implement ví dụ &lt;strong>&amp;ldquo;kinh điển&amp;rdquo;&lt;/strong> của &lt;code>Race Condition&lt;/code> là increase một biến &lt;code>counter&lt;/code> bằng 3 cách: increase bình thường, increase với Map-Reduce và increase với nhiều thread và AtomicLong.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Array&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">&amp;gt;)&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">max&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1000&lt;/span>&lt;span class="n">_000_000L&lt;/span> &lt;span class="c1">// the max value which counter need increase to this
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// increase use one thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">var&lt;/span> &lt;span class="py">counterSync&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">0L&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">timeSync&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">measureNanoTime&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">counterSync&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">increaseSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;increaseSync: counterSync [&lt;/span>&lt;span class="si">$counterSync&lt;/span>&lt;span class="s2">] - time [&lt;/span>&lt;span class="si">$timeSync&lt;/span>&lt;span class="s2">]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">workers&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">5&lt;/span> &lt;span class="c1">// number workers to split into sub many increment
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">var&lt;/span> &lt;span class="py">counterMapReduce&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">0L&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">timeMapReduce&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">measureNanoTime&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">counterMapReduce&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">increaseMapReduce&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">workers&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;increaseSync with Map-Reduce: counterMapReduce [&lt;/span>&lt;span class="si">${counterMapReduce}&lt;/span>&lt;span class="s2">] - time [&lt;/span>&lt;span class="si">$timeMapReduce&lt;/span>&lt;span class="s2">]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">var&lt;/span> &lt;span class="py">atomicCounter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">AtomicLong&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">timeAtomicCounter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">measureNanoTime&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">increaseWithAtomic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">workers&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">atomicCounter&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;increaseWithAtomic: atomicCounter [&lt;/span>&lt;span class="si">${atomicCounter.get()}&lt;/span>&lt;span class="s2">] - time [&lt;/span>&lt;span class="si">$timeAtomicCounter&lt;/span>&lt;span class="s2">]&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// just use for statement in one thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fun&lt;/span> &lt;span class="nf">increaseSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Long&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">Long&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">var&lt;/span> &lt;span class="py">counter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">0L&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="m">0&lt;/span> &lt;span class="n">until&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">counter&lt;/span>&lt;span class="o">++&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">counter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// create workers group then increase couter in each worker and sum it
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">suspend&lt;/span> &lt;span class="k">fun&lt;/span> &lt;span class="nf">increaseMapReduce&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Long&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">workers&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">Long&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">maxByWorker&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">max&lt;/span> &lt;span class="p">/&lt;/span> &lt;span class="n">workers&lt;/span> &lt;span class="c1">// max counter of each worker
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">threadPool&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">newFixedThreadPoolContext&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">workers&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;workerThreadPool&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// workers group
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="m">1.&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">workers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">threadPool&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">increaseSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">maxByWorker&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// create worker jobs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">await&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// wait all jobs of workers done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">reduce&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">acc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">current&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">acc&lt;/span> &lt;span class="p">+&lt;/span> &lt;span class="n">current&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// sum max counter of each worker
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// create thread group and shared couter, each thread will increase shared couter and wait all threads done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fun&lt;/span> &lt;span class="nf">increaseWithAtomic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Long&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">workers&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">atomicCounter&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AtomicLong&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">maxByWorker&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">max&lt;/span> &lt;span class="p">/&lt;/span> &lt;span class="n">workers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">threads&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="m">1.&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">workers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="n">map&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="c1">// create thread group
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">thread&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="m">0&lt;/span> &lt;span class="n">until&lt;/span> &lt;span class="n">maxByWorker&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">atomicCounter&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">incrementAndGet&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// increase atomic opertation
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">thread&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="n">threads&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// wait all threads done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">thread&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>kết quả sẽ show ra như sau:&lt;/p>
&lt;pre tabindex="0">&lt;code>increaseSync: counterSync [1000000000] - time [304001418]
increaseSync with Map-Reduce: counterMapReduce [1000000000] - time [171316295]
increaseWithAtomic: atomicCounter [1000000000] - time [19268418252]
&lt;/code>&lt;/pre>&lt;p>Ta có thể thấy thời gian của &lt;code>increaseSync with Map-Reduce&lt;/code> là nhanh nhất ta xem là &lt;strong>1x&lt;/strong> thì &lt;code>increaseSync&lt;/code> là &lt;strong>1.8x&lt;/strong> và thật kinh khủng khi &lt;code>increaseWithAtomic&lt;/code> là &lt;strong>112.5x&lt;/strong>. Số liệu chạy lại có thể khác nhưng từ đây có thể thấy trong trường hợp thời gian thực hiện toán tử là nhanh và thời gian để đảm bảo &lt;code>shared state&lt;/code> luôn đúng là chậm thì &lt;em>&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#UseSynchronizationsOrAtomicOperations">Sử dụng Synchronizations hoặc Atomic Operations&lt;/a>&lt;/em> là không hiệu quả.&lt;/p>
&lt;p>&lt;strong>Kết:&lt;/strong> Khi giải quyết &lt;code>Race Condition&lt;/code> trong thời điểm hiện tại thì cách &lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#AvoidShareState">Tránh chia sẻ trạng thái&lt;/a> đang là giải pháp tối ưu trong hầu hết các trường hợp, &lt;code>Map-Reduce&lt;/code> là một trong những hiện thực của cách trên nhưng vẫn còn những cách khác giải quyết những vấn đề phức tạp hơn. Mong các bạn đón đọc phần tiếp theo của loại bài viết về &lt;a href="https://trile.dev/categories/coroutines">&lt;code>Kotlin Coroutines&lt;/code>&lt;/a> để được nhiều vấn đề trong &lt;code>Concurrent&lt;/code> và cách giải quyết nhé.&lt;/p>
&lt;p>Phần code sample mình update vào &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/coroutines-advanced">repo này&lt;/a> nhé. Cảm ơn các bạn đã đọc tới đây.
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Trong một thời điểm chỉ một &lt;code>thread&lt;/code> được phép thực thi.&amp;#160;&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>Là các thao tác *&lt;em>không thể chia nhỏ ra nữa&lt;/em> trong đó ngôn ngôn ngữ lập trình hoặc hệ điều hành sẽ đảm bảo các thao tác này sẽ hoàn thành một cách độc lập với bất kỳ &lt;code>thread&lt;/code> hoặc &lt;code>process&lt;/code> nào.&amp;#160;&lt;a href="https://trile.dev/post/2020-07-04-resolve-race-condition-problems-with-map-reduce-and-coroutines/#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description><category domain="https://trile.dev/categories/kotlin/">Kotlin</category><category domain="https://trile.dev/categories/coroutines/">Coroutines</category><category domain="https://trile.dev/tags/kotlin/">kotlin</category><category domain="https://trile.dev/tags/coroutines/">coroutines</category><category domain="https://trile.dev/tags/race-condition/">race-condition</category><category domain="https://trile.dev/tags/map-reduce/">map-reduce</category><category domain="https://trile.dev/tags/performance/">performance</category></item><item><title>Kotlin Coroutines Basic Concepts</title><link>https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/</link><guid isPermaLink="true">https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/</guid><pubDate>Sun, 31 May 2020 10:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Mở đầu loại bài viết về &lt;a href="https://github.com/Kotlin/kotlinx.coroutines">&lt;code>Kotlin Coroutines&lt;/code>&lt;/a> mình sẽ giải thích khác khái niệm trong &lt;code>Coroutines&lt;/code> và tương ứng với các khái niệm sẽ có thêm ví dụ. Qua đó mong bạn sẽ có kiến thức nền về &lt;code>Coroutines&lt;/code> và tìm hiểu nó nhanh hơn.&lt;/p>
&lt;p>Các khái niệm sẽ giải thích trong bài này:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Dispatchers">Dispatchers&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Scope">Scope&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Context">Context&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#SuspendingFunction">Suspending Function&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Job">Job&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Deferred">Deferred&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="Dispatchers">1. Dispatchers&lt;/h3>
&lt;p>Đúng như cái tên. &lt;code>Dispatcher&lt;/code> có nhiệm vụ điều phối một hoặc nhiều thread làm nhiệm vụ thực thi &lt;code>coroutine&lt;/code>. Có các loại &lt;code>Dispatcher&lt;/code> như sau:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-default.html">Dispatchers.Default&lt;/a>: là dispatcher mặc định sẽ được sử dụng nếu không khai báo tường minh trong &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#ScopeBuilder">Scope Builder&lt;/a>. Nó sử dụng một &lt;code>common pool&lt;/code> được chia sẻ bởi các thread nền. &lt;code>Dispatchers.Default&lt;/code> thích hợp với các tính toán cần nhiều tài nguyên CPU&lt;/li>
&lt;li>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html">Dispatchers.IO&lt;/a>: được thiết kế để sử dụng cho các thao tác &lt;code>IO-intensive blocking operations&lt;/code> như đọc/ghi file hay blocking socket I/O&lt;/li>
&lt;li>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-unconfined.html">Dispatchers.Unconfined&lt;/a>: đây là một dispatcher khá lạ. Trong docs cũng nói nó &lt;strong>không thường được sử dụng trong code&lt;/strong> ;)). Dispatchers này sẽ không chỉ định thread nào sẽ thực thi. Nó có nghĩa là khi khởi chạy nó sẽ được chạy bởi thread đang chạy nó, khi &lt;code>resume&lt;/code> lại sau khi &lt;code>suspend&lt;/code> thì &lt;code>Coroutines&lt;/code> sẽ quyết định thread sẽ thực thi&lt;/li>
&lt;li>ThreadPool cụ thể được chỉ định được tạo ra bởi &lt;code>newSingleThreadContext&lt;/code> hoặc &lt;code>newFixedThreadPoolContext&lt;/code>&lt;/li>
&lt;li>Các &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html">Executor&lt;/a> được convert bởi &lt;code>asCoroutineDispatcher&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// context of the parent, main runBlocking coroutine
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;main runBlocking : I&amp;#39;m working in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">Dispatchers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Unconfined&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// not confined -- will work with main thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Unconfined : I&amp;#39;m working in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">Dispatchers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Default&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// will get dispatched to DefaultDispatcher
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Default : I&amp;#39;m working in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">newCoroutineContext&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">Dispatchers&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Default&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// will get its own new thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;newCoroutineContext : I&amp;#39;m working in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">//
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">dispatcherWithTwoThread&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">newFixedThreadPoolContext&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;ThreadPoll&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repeat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dispatcherWithTwoThread&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// will get its own new thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;dispatcherWithTwoThread&lt;/span>&lt;span class="si">${it.padEnd(3)}&lt;/span>&lt;span class="s2"> : I&amp;#39;m working in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">Random&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nextLong&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">5000&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;dispatcherWithTwoThread&lt;/span>&lt;span class="si">${it.padEnd(3)}&lt;/span>&lt;span class="s2"> : I&amp;#39;m done in thread &lt;/span>&lt;span class="si">${Thread.currentThread().name}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">Int&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">padEnd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">padChar&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Char&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sc">&amp;#39;0&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">toString&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">padStart&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">padChar&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="Scope">2. Scope&lt;/h3>
&lt;p>Các &lt;code>coroutine&lt;/code> được khởi chạy trong &lt;code>CoroutineScope&lt;/code>. Mục đích của việc này để quản lý resource. Hãy tưởng tượng khi ta cần thực hiện một tác vụ nặng nào đó trong một hoặc nhiều &lt;code>coroutine&lt;/code>, nhưng giữa chừng tác vụ đó không cần thiết nữa, lúc này ta chỉ cần &lt;code>cancel()&lt;/code> scope chứa các coroutine của tác vụ nặng trên. Một đặc điểm khác của &lt;code>CoroutineScope&lt;/code> là nó có thể chứa nhiều &lt;code>CoroutineScope&lt;/code> con.&lt;/p>
&lt;h5 id="GlobalScope">GlobalScope&lt;/h5>
&lt;p>&lt;code>GlobalScope&lt;/code> được xem như là scope cha của tất cả các &lt;code>CoroutineScope&lt;/code> trong ứng dụng. &lt;code>GlobalScope&lt;/code> không thể bị &lt;code>cancel()&lt;/code> và sẽ tồn tại xuyên suốt vòng đời ứng dụng. Ngoài ra việc sử dụng được khuyên là &lt;strong>KHÔNG NÊN&lt;/strong>. Bạn có thể xem thêm ở bài &lt;a href="https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc">The reason to avoid GlobalScope&lt;/a> để hiểu nguyên nhân nhé.&lt;/p>
&lt;h5 id="ScopeBuilder">Scope Builder&lt;/h5>
&lt;p>Như đã nói ở trên các &lt;code>coroutine&lt;/code> sẽ được khởi chạy trong các &lt;code>Scope Builder&lt;/code> sau:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html">runBlocking&lt;/a>: chạy một &lt;code>coroutine&lt;/code> và sẽ &lt;strong>block&lt;/strong>&lt;sup id="fnref:1">&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> đến khi &lt;code>coroutine&lt;/code> bên trong chạy xong. &lt;strong>Không nên&lt;/strong> sử dụng function này trong một &lt;code>coroutine&lt;/code> vì nó được thiết kế để làm &lt;code>cầu nối&lt;/code> code thường với các thư viện được viết theo &lt;code>suspending style&lt;/code>, thường được sử dụng cho hàm &lt;code>main&lt;/code> và trong test.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html">coroutineScope&lt;/a>: Tạo ra một &lt;code>CoroutineScope&lt;/code> mới. Scope được tạo mới này là con của scope bên ngoài nhưng overrides lại &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Job">Job&lt;/a>. Function này được thiết kết để &lt;code>parallel decomposition&lt;/code>, nghĩa là khi có bất cứ một &lt;code>coroutine&lt;/code> nào fail trong scope này thì các &lt;code>coroutine&lt;/code> đang đợi xử lý trong scope này cũng sẽ được &lt;code>cancel&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html">launch&lt;/a>: Tạo ra một &lt;code>CoroutineScope&lt;/code> mới, sẽ &lt;strong>không block&lt;/strong>&lt;sup id="fnref:2">&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> thread hiện tại và sẽ trả về một &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Job">Job&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html">async&lt;/a>: Tạo ra một &lt;code>CoroutineScope&lt;/code> mới, sẽ &lt;strong>không block&lt;/strong>&lt;sup id="fnref1:2">&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup> thread hiện tại và sẽ trả về một &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Deferred">Deferred&lt;/a>. Như vậy &lt;code>async&lt;/code> được dùng khi cần kết quả trả về khi gọi còn &lt;code>launch&lt;/code> thì không.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">job&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;parent&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// parent scope
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Start &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;child-1&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Start &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;End &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;child-2&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Start &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;End &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// not execute this line
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;End &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// still wait child-1 and child-2 finish
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">2000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">job&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cancel&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// cancel but child-2 not finish
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Done&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="Context">3. Context&lt;/h3>
&lt;p>Mỗi &lt;code>coroutine&lt;/code> trong &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> đều có một &lt;code>context&lt;/code> được thể hiện bằng một instance của interface &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/">&lt;code>CoroutineContext&lt;/code>&lt;/a>. Context này là một tập các thành phần cấu hình cho coroutine, trong đó 2 thành phần quan trọng là &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Job">Job&lt;/a> và &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Dispatcher">Dispatcher&lt;/a>.&lt;/p>
&lt;p>&lt;code>Context&lt;/code> là một &lt;code>immutable&lt;/code>. Nhưng ta có thể dùng toán tử &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-coroutine-context/plus.html">&lt;code>plus&lt;/code>&lt;/a> để tạo ra một &lt;code>context&lt;/code> mới.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Unit&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Current context is: &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;New context with name: &lt;/span>&lt;span class="si">${coroutineContext + CoroutineName(&amp;#34;test&amp;#34;)}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Job in current context is: &lt;/span>&lt;span class="si">${coroutineContext[Job]}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Dispatcher in current context is: &lt;/span>&lt;span class="si">${coroutineContext[ContinuationInterceptor]}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;child&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Child context is &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">}&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;CoroutineName in current context is: &lt;/span>&lt;span class="si">${coroutineContext[CoroutineName]}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="SuspendingFunction">4. Suspending Function&lt;/h3>
&lt;p>&lt;code>Suspending Function&lt;/code> được xem xương sống của &lt;a href="https://github.com/Kotlin/kotlinx.coroutines">&lt;code>Kotlin Coroutines&lt;/code>&lt;/a>. Khi đó, các function bên trong &lt;code>Suspending Function&lt;/code> sẽ được gọi mà không bị &lt;strong>block&lt;/strong>&lt;sup id="fnref1:1">&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>. Như thế thread đang handle cho &lt;code>Suspending Function&lt;/code> sẽ được trả lại cho &lt;code>JVM&lt;/code> và được dùng cho các tác vụ khác.
&lt;code>Suspending Function&lt;/code> phải chạy trong một &lt;code>coroutine&lt;/code> thì mới có tác dụng nhé ;))&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;parent&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">+&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">newSingleThreadContext&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;SingleThread&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// Dispatcher SingleThread only use one thread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CoroutineName&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;child&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">doSomeThingToWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// release thread in SingleThread for another function
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">doSomeThingToWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// use thread in SingleThread
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">suspend&lt;/span> &lt;span class="k">fun&lt;/span> &lt;span class="nf">doSomeThingToWait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">waitTime&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Long&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Current context when START: &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">waitTime&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// simulator processing
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Current context when END : &lt;/span>&lt;span class="si">$coroutineContext&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="Job">5. Job&lt;/h3>
&lt;p>Như đã đề cập ở &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Context">Context&lt;/a> &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html">&lt;code>Job&lt;/code>&lt;/a> là thành phần không thể thiếu trong &lt;code>context&lt;/code>. Nó cho phép ta &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/cancel.html">&lt;code>cancel()&lt;/code>&lt;/a>, &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html">&lt;code>join()&lt;/code>&lt;/a> hoặc &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/start.html">&lt;code>start()&lt;/code>&lt;/a> &lt;code>coroutine&lt;/code> tương ứng với &lt;code>job&lt;/code> đó. Ngoài ra nhờ có &lt;code>job&lt;/code> mà ta biết được trạng thái của một &lt;code>coroutine&lt;/code>. Các trạng thái của &lt;code>coroutine&lt;/code> có thể được biển diễn ở hình dưới:&lt;/p>
&lt;pre tabindex="0">&lt;code> wait children
+-----+ start +--------+ complete +-------------+ finish +-----------+
| New | -----&amp;gt; | Active | ---------&amp;gt; | Completing | -------&amp;gt; | Completed |
+-----+ +--------+ +-------------+ +-----------+
| cancel / fail |
| +----------------+
| |
V V
+------------+ finish +-----------+
| Cancelling | --------------------------------&amp;gt; | Cancelled |
+------------+ +-----------+
&lt;/code>&lt;/pre>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">timeNotCancel&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">measureTimeMillis&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">job&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">launch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// done after 3000 ms
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">job&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// wait job done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Time to run not cancel &lt;/span>&lt;span class="si">$timeNotCancel&lt;/span>&lt;span class="s2"> ms&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">timeWithCancel&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">measureTimeMillis&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">job&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">launch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// done after 3000 ms
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">job&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cancel&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// not wait delay(3_000)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">job&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// wait job done
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Time to run with cancel &lt;/span>&lt;span class="si">$timeWithCancel&lt;/span>&lt;span class="s2"> ms&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="Deferred">6. Deferred&lt;/h3>
&lt;p>&lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/">Deferred&lt;/a> cũng là một &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#Job">&lt;code>Job&lt;/code>&lt;/a> nhưng nó chứa kết quả khi &lt;code>coroutine&lt;/code> hoàn thành. &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/">Deferred&lt;/a> được tạo bằng &lt;code>async&lt;/code> mà mình đã đề cập ở &lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#ScopeBuilder">ScopeBuilder&lt;/a> hoặc khởi tạo trực tiếp bởi &lt;a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-completable-deferred/index.html">CompletableDeferred&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--------- async ---------&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">deferred&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">async&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">getRandomInt&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Wait async-getRandomInt result&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RandomInt from async-getRandomInt = &lt;/span>&lt;span class="si">${deferred.await()}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;------ CompletableDeferred ------&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">completableDeferred&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">CompletableDeferred&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">Int&lt;/span>&lt;span class="p">&amp;gt;()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">launch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nc">Random&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nextInt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;completableDeferred done with result &lt;/span>&lt;span class="si">$result&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">completableDeferred&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">complete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Wait completableDeferred result&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;RandomInt from completableDeferred = &lt;/span>&lt;span class="si">${completableDeferred.await()}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">suspend&lt;/span> &lt;span class="k">fun&lt;/span> &lt;span class="nf">getRandomInt&lt;/span>&lt;span class="p">():&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nc">Random&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nextInt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">10&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;async-getRandomInt done with result &lt;/span>&lt;span class="si">$result&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Phần code sample mình update vào &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/coroutines-basic">repo này&lt;/a> nhé. Cảm ơn các bạn đã đọc tới đây.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Thread hiện tại sẽ đợi đến khi function chạy xong thì mới chạy tiếp đoạn code tiếp theo&amp;#160;&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&amp;#160;&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fnref1:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>Chạy tiếp đoạn code tiếp theo mà không phải đợi function này hoàn tất. Kết quả sẽ trả về qua &lt;code>callback&lt;/code> hoặc một &lt;code>feature object&lt;/code>&amp;#160;&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&amp;#160;&lt;a href="https://trile.dev/post/2020-05-31-kotlin-coroutine-basic-concepts/#fnref1:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description><category domain="https://trile.dev/categories/kotlin/">Kotlin</category><category domain="https://trile.dev/categories/coroutines/">Coroutines</category><category domain="https://trile.dev/tags/kotlin/">kotlin</category><category domain="https://trile.dev/tags/coroutines/">coroutines</category></item><item><title>How to use Kotlin in Java project</title><link>https://trile.dev/post/2020-05-24-how-to-use-kotlin-in-java-project/</link><guid isPermaLink="true">https://trile.dev/post/2020-05-24-how-to-use-kotlin-in-java-project/</guid><pubDate>Sun, 24 May 2020 10:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>In the article &lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language">Introduction to the Kotlin Language&lt;/a>, I introduced &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> and promised to share my experience in the process of integrating &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>. This is one of the articles in that series.&lt;/p>
&lt;p>First, we need a &lt;code>Java project&lt;/code>, and I chose the project sample from the article &lt;a href="https://trile.dev/post/2020-03-15-custom-exception">Custom Exception&lt;/a> and &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/custom-exception">this repo&lt;/a>!&lt;/p>
&lt;p>Run the following commands (you can copy and run them at once):&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># clone git sample repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://gitlab.com/thanhtrixx/trile-dev-sample/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> trile-dev-sample/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># copy to new project&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cp -r custom-exception how-to-use-kotlin-in-java-project
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Open the IDE. Here, I&amp;rsquo;m using &lt;a href="https://www.jetbrains.com/idea/">IntelliJ IDEA CE&lt;/a> and follow these steps:&lt;/p>
&lt;h3 id="UpdateGradle">1. Update Gradle build config&lt;/h3>
&lt;p>Rename the project (skip this step if you don&amp;rsquo;t need to rename it). Open the &lt;code>settings.gradle&lt;/code> file and update it as follows:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">rootProject&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;how-to-use-kotlin-in-java-project&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Add &lt;code>plugins&lt;/code> in file &lt;code>build.gradle&lt;/code> file:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Apply the Kotlin JVM plugin to add support for Kotlin.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">id&lt;/span> &lt;span class="s1">&amp;#39;org.jetbrains.kotlin.jvm&amp;#39;&lt;/span> &lt;span class="n">version&lt;/span> &lt;span class="s2">&amp;#34;${kotlin_version}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Similarly, update &lt;code>dependencies&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Reflection is a set of language and library features that allows you to introspect the structure of your program at runtime.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">implementation&lt;/span> &lt;span class="s1">&amp;#39;org.jetbrains.kotlin:kotlin-reflect&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Reflection is a set of language and library features that allows you to introspect the structure of your program at runtime.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">implementation&lt;/span> &lt;span class="s1">&amp;#39;org.jetbrains.kotlin:kotlin-stdlib&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Add config for &lt;code>compileKotlin&lt;/code> and build &lt;code>jar file&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">tasks&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">withType&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">KotlinCompile&lt;/span>&lt;span class="o">).&lt;/span>&lt;span class="na">configureEach&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">kotlinOptions&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">freeCompilerArgs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="s1">&amp;#39;-Xjsr305=strict&amp;#39;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">jvmTarget&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">jdk_version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sourceCompatibility&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">jdk_version&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">jar&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// This line of code recursively collects and copies all of a project&amp;#39;s files
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// and adds them to the JAR itself. One can extend this task, to skip certain
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// files or particular types at will
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">from&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="n">configurations&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">compileClasspath&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">collect&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="n">it&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">isDirectory&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">it&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">zipTree&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">it&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">}&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">duplicatesStrategy&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">DuplicatesStrategy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">EXCLUDE&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Finally, add &lt;code>gradle.properties&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-properties" data-lang="properties">&lt;span class="line">&lt;span class="cl">&lt;span class="na">kotlin_version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">1.8.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">jdk_version&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">17&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="KotlinCallJava">2. Kotlin call Java&lt;/h3>
&lt;p>Create a directory to store &lt;code>Kotlin class&lt;/code>. The rule is that &lt;code>.kt&lt;/code> files of &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> must be placed in the &lt;code>src/main/kotlin&lt;/code> directory:&lt;/p>
&lt;pre tabindex="0">&lt;code>mkdir -p src/main/kotlin/dev/trile/java2kotlin
&lt;/code>&lt;/pre>&lt;p>Create &lt;code>KotlinSalaryTransfer&lt;/code> class with the provided content:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">KotlinSalaryTransfer&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">moneyTransfer&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">MoneyTransfer&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">private&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">salaryCalculator&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">SalaryCalculator&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fun&lt;/span> &lt;span class="nf">salaryTransfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">workingDay&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">salary&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">salaryCalculator&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">calcSalary&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">workingDay&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">moneyTransfer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">transferMoney&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">salary&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Transfer Salary success&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Array&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">&amp;gt;)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">salaryTransfer&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">SalaryTransfer&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">salaryTransfer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">salaryTransfer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">toInt&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="m">1&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="n">toInt&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">NumberFormatException&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Parse int error &amp;#34;&lt;/span> &lt;span class="p">+&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="build-và-chạy-thử">Build và chạy thử&lt;/h5>
&lt;pre tabindex="0">&lt;code># build
./gradlew clean build
# run
java -cp build/libs/*.jar dev.trile.java2kotlin.KotlinSalaryTransferKt 11 1000000 EM1
&lt;/code>&lt;/pre>&lt;p>Please check the result to see if it matches the &lt;a href="https://trile.dev/post/2020-03-15-custom-exception#BuildAndTest">Custom Exception&lt;/a> article ;))&lt;/p>
&lt;h3 id="JavaCallKotlinC">3. Java call Kotlin&lt;/h3>
&lt;p>Rewrite the &lt;code>VietcomBank&lt;/code> class using &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> kotlin:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">VietcomBank&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">Bank&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Throws&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SalaryException&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="k">class&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">override&lt;/span> &lt;span class="k">fun&lt;/span> &lt;span class="nf">transferMoney&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">checkTransferParams&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="p">&amp;gt;&lt;/span> &lt;span class="m">10000000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nc">ErrorType&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">TRANSFER_MONEY_NOT_ENOUGH_MONEY&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;VCB only support transfer amount less than 10M&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;VCB Kotlin transfer success&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Update &lt;code>MoneyTransfer&lt;/code> to use the new &lt;code>VietcomBank&lt;/code> class:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// private final Bank vietcomBank = new VietcomBank();
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">private&lt;/span> &lt;span class="kd">final&lt;/span> &lt;span class="n">Bank&lt;/span> &lt;span class="n">vietcomBank&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">dev&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">trile&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">java2kotlin&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">VietcomBank&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="BuildAndTest">Build and test&lt;/h5>
&lt;pre tabindex="0">&lt;code># build
./gradlew clean build
# run
java -cp build/libs/*.jar dev.trile.java2kotlin.KotlinSalaryTransferKt 5 1000000 EM1
&lt;/code>&lt;/pre>&lt;p>The result will be updated as follows:&lt;/p>
&lt;pre tabindex="0">&lt;code>Transfer 5000000 to EM1
VCB Kotlin transfer success
Transfer Salary success
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Conclusion:&lt;/strong> With this article, you will learn the first step to integrate &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> into &lt;code>Java&lt;/code>, but the complete transition to &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> is a long journey. I will write a few more articles to make it easier for those who want to join me on this journey ;))&lt;/p>
&lt;p>I updated the code sample in &lt;a href="https://github.com/thanhtrixx/trile-dev-sample/tree/master/how-to-use-kotlin-in-java-project">this repo&lt;/a>. Thank you for reading this far.&lt;/p>
&lt;p>&lt;strong>Update&lt;/strong>: I have made updates to the content of &lt;code>build.gradle&lt;/code> and &lt;code>gradle.properties&lt;/code> to align with the development of Kotlin and Java.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/5bdhq6YF0szPaCEk9Y/giphy.mp4">&lt;/video>
&lt;/div></description><category domain="https://trile.dev/categories/kotlin/">Kotlin</category><category domain="https://trile.dev/categories/from-java-to-kotlin/">From Java to Kotlin</category><category domain="https://trile.dev/tags/kotlin/">kotlin</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/java-to-kotlin/">java-to-kotlin</category><category domain="https://trile.dev/tags/gradle/">gradle</category></item><item><title>Introduction to the Kotlin Language</title><link>https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/</link><guid isPermaLink="true">https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/</guid><pubDate>Sun, 17 May 2020 02:30:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Nếu:&lt;/p>
&lt;ul>
&lt;li>Bạn là một lập trình viên &lt;code>Java&lt;/code> và đã chán ngấy với cú pháp dài dòng của nó&lt;/li>
&lt;li>Bạn là một &lt;code>developer&lt;/code> và bạn muốn code ít hơn để được về sớm hơn ;))&lt;/li>
&lt;li>Bạn là một &lt;code>leader&lt;/code> và bạn đang phải viết report cho việc có bug trên live do review code quá nhiều&lt;/li>
&lt;li>Bạn theo triết lý &lt;code>less code less bug&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>thì &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> có thể giúp bạn ;))&lt;/p>
&lt;blockquote>
&lt;p>Đến với nhau vì ưu điểm &lt;br>
Rời xa nhau vì những hiểu lầm &lt;br>
— &lt;cite>&lt;a href="https://trile.dev/about">Trí Xàm ;))&lt;/a>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;p>Vì thế sau đây mình là những ưu điểm của &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> so với &lt;code>Java&lt;/code> và từ đó mong bạn sẽ có động lực để tìm hiểu &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>.&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#JVMLanguage">JVM language&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#CleanSyntax">Clean, compact, sugar syntax&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#NullSafety">Null safety&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#UncheckedExceptions">Unchecked exceptions&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#DataClasses">Data classes&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#DefaultValues">Default values&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#NamedArguments">Named arguments&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#FunctionalProgramingSupport">Functional programing support&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#ExtensionFunctions">Extension functions&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#Coroutines">Coroutines: lightweight thread&lt;/a>&lt;/li>
&lt;/ol>
&lt;h3 id="JVMLanguage">1. JVM language&lt;/h3>
&lt;p>&lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> cũng giống các ngôn ngữ như &lt;code>Scala&lt;/code>, &lt;code>Clojure&lt;/code>, &lt;code>Grovvy&lt;/code>&amp;hellip; đều là ngôn ngữ JVM (&lt;a href="https://en.wikipedia.org/wiki/List_of_JVM_languages">full list&lt;/a>). Vì thế mà nó sẽ có được các ưu điểm sau:&lt;/p>
&lt;ul>
&lt;li>Được build thành &lt;code>bytecode&lt;/code> và chạy trên &lt;code>JRE (Java Runtime Environment)&lt;/code>: sử dụng lại được cơ sở hạn tầng có sẵn.&lt;/li>
&lt;li>Sử dụng chung hệ sinh thái và thư viện của &lt;code>Java&lt;/code>: là một trong những ngôn ngữ phổ biến nhất &lt;code>Java&lt;/code> có một hệ sinh thái và thư viện đồ sộ của &lt;code>Java&lt;/code>. Bạn sẽ không phải tốn quá nhiều thời gian để tìm hoặc viết lại các thư viện khi thay đổi ngôn ngữ.&lt;/li>
&lt;li>Tương tác được với code &lt;code>Java&lt;/code> trong cùng một module/project: bạn có một module/project đang viết bằng &lt;code>Java&lt;/code>. Bạn sẽ không cần phải port lại 100% mà chỉ cần một số config build thì bạn đã có được một module/project mà được code bằng cả &lt;code>Java&lt;/code> và &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>. Các này rất thích hợp cho những module/project yêu cầu tính &lt;code>an toàn&lt;/code> và &lt;code>ổn định&lt;/code>. Cá nhân người viết cũng đã tiếp nhận vài project viết bằng &lt;code>Java&lt;/code> và đã chuyển sang tích hợp &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> được gần 2 năm rồi. Khối lượng code &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> chỉ chiếm &lt;code>35%&lt;/code> nhưng khối lượng logic đang xử lý thì ước lượng khoảng &lt;code>70%&lt;/code>&lt;/li>
&lt;/ul>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/JOYKhqydse2bkbYFmb/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Mình sẽ viết một vài bài chia sẻ kinh nghiệm và chiến lượt convert từ &lt;code>Java&lt;/code> sang &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>. Mong các bạn đón nhận!!&lt;/p>
&lt;p>&lt;strong>Update&lt;/strong>: loạt bài mình nói nè &lt;a href="https://trile.dev/categories/from-java-to-kotlin">From Java to Kotlin&lt;/a>&lt;/p>
&lt;h3 id="CleanSyntax">2. Clean, compact, sugar syntax&lt;/h3>
&lt;p>Để nói về việc &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> giúp code ngắn gọn thế nào có khi phải cần một vài bài nhưng trong chapter này mình chỉ nêu một vài đặc điểm mình cho là hay nhất. Ở đây mình xem các bạn đã rành &lt;code>Java&lt;/code> rồi nên sẽ k có code &lt;code>Java&lt;/code> tương ứng. Còn nếu bạn chưa rành &lt;code>Java&lt;/code> thì chơi &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> luôn đê.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/fGCa0O9sogzEOTbBaP/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h5 id="main-function">Main function&lt;/h5>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Hello world!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="functions">Functions&lt;/h5>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="p">+&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>ngắn gọn hơn&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="p">+&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="variables">Variables&lt;/h5>
&lt;p>&lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> hỗ trợ 2 keywords là &lt;code>val&lt;/code> và &lt;code>var&lt;/code> để khai báo biến. Kiểu biến nếu không khai báo tường minh sẽ lấy từ giá trị.
&lt;code>val&lt;/code> và &lt;code>var&lt;/code> khác nhau ở chỗ &lt;code>val&lt;/code> không cho phép set lại giá trị, còn &lt;code>var&lt;/code> thì cho&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">a&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1&lt;/span> &lt;span class="c1">// immediate assignment
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">b&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">2&lt;/span> &lt;span class="c1">// `Int` type is inferred
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">c&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="c1">// Type required when no initializer is provided
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">3&lt;/span> &lt;span class="c1">// deferred assignment
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="string-templates">String templates&lt;/h5>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">var&lt;/span> &lt;span class="py">a&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// simple name in template:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">s1&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;a is &lt;/span>&lt;span class="si">$a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">a&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// arbitrary expression in template:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">s2&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">${s1.replace(&amp;#34;is&amp;#34;, &amp;#34;was&amp;#34;)}&lt;/span>&lt;span class="s2">, but now is &lt;/span>&lt;span class="si">$a&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="statement-as-expression">Statement as expression&lt;/h5>
&lt;p>Các statement như &lt;code>if/else&lt;/code>, &lt;code>try/catch&lt;/code>, &lt;code>when&lt;/code> có thể là một expression nếu cần&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">bigger&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="n">b&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">color&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">when&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">relax&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">GREEN&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">studyTime&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">YELLOW&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">BLUE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">object&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gson&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">fromJson&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Throwable&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="type-checks-and-automatic-casts">Type checks and automatic casts&lt;/h5>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">getStringLength&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">obj&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Any&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">obj&lt;/span> &lt;span class="o">!is&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="k">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// `obj` is automatically cast to `String` in this branch
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h5 id="remove-new-keyword">Remove &lt;code>new&lt;/code> keyword&lt;/h5>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">rectangle&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Rectangle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">5.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">2.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">triangle&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Triangle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">3.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">4.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">5.0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="NullSafety">3. Null safety&lt;/h3>
&lt;p>Chắc các bạn cũng biết &lt;a href="https://hinchman-amanda.medium.com/null-pointer-references-the-billion-dollar-mistake-1e616534d485">Null là một lỗi thiết kế trị giá tỷ đô&lt;/a> và để loại bỏ nó &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> cung cấp cho ta các công cụ rất mạnh.&lt;/p>
&lt;p>Mặc định &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> không cho phép biến chứa giá trị &lt;code>null&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">var&lt;/span> &lt;span class="py">a&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;abc&amp;#34;&lt;/span> &lt;span class="c1">// Regular initialization means non-null by default
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">null&lt;/span> &lt;span class="c1">// compilation error
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Để cho phép biến chứa giá trị &lt;code>null&lt;/code> cần khai báo tường minh:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">var&lt;/span> &lt;span class="py">b&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;abc&amp;#34;&lt;/span> &lt;span class="c1">// can be set null
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">null&lt;/span> &lt;span class="c1">// ok
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Không gọi hàm với biến có thể &lt;code>null&lt;/code> được&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">l&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span> &lt;span class="c1">// error: variable &amp;#39;b&amp;#39; can be null
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Để gọi được cần thêm &lt;code>?.&lt;/code> khi đó kết quả có thể &lt;code>null&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">l&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="o">?.&lt;/span>&lt;span class="n">length&lt;/span> &lt;span class="c1">// l is nullable
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Kiểm tra &lt;code>null&lt;/code> với &lt;code>b&lt;/code> và &lt;code>l&lt;/code> = 0 nếu &lt;code>b == null&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">l&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="o">?.&lt;/span>&lt;span class="n">length&lt;/span> &lt;span class="o">?:&lt;/span> &lt;span class="m">0&lt;/span> &lt;span class="c1">// if (b == null) then l = 0 else l = b.length
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Safe Casts&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">aInt&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="k">as&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="c1">// aInt: Int?
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">aIntDefault&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="k">as&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="o">?:&lt;/span> &lt;span class="m">0&lt;/span> &lt;span class="c1">// val aInt = if (a !is Int) 0 else a as Int
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="UncheckedExceptions">4. Unchecked exceptions&lt;/h3>
&lt;p>Ở bài &lt;a href="https://trile.dev/post/2020-04-22-try-catch-explain#CheckedAndUnCheckedExceptions">&lt;code>Try/Catch Explain&lt;/code>&lt;/a> mình cũng đã nói không thích nó.
Tất nhiên không phải mình mà còn rất nhiều các bài khác:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://phauer.com/2015/checked-exceptions-are-evil/">Checked Exceptions are Evil&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://medium.com/@OhadShai/its-almost-2020-and-yet-checked-exceptions-are-still-a-thing-bfaa24c8997e">It’s almost 2020 and yet… Checked Exceptions are still a thing&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://news.ycombinator.com/item?id=18050294">Java’s Checked Exceptions Are Evil? (2015)&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Và thật là may mắn khi khi tất cả các &lt;code>Exception&lt;/code> trong &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> là &lt;code>Unchecked exceptions&lt;/code> ;))&lt;/p>
&lt;h3 id="DataClasses">5. Data classes&lt;/h3>
&lt;p>Giả sử ta cần khai báo một class &lt;code>User&lt;/code> gồm 2 fields &lt;code>name&lt;/code> và &lt;code>age&lt;/code> với &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> ta chỉ cần:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">data&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">age&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Khi này &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> sẽ tự động tạo ra các method:&lt;/p>
&lt;ul>
&lt;li>Các &lt;code>getter&lt;/code>/&lt;code>setter&lt;/code>&lt;/li>
&lt;li>&lt;code>equals()&lt;/code>/&lt;code>hashCode()&lt;/code>&lt;/li>
&lt;li>&lt;code>toString()&lt;/code> có dạng: &lt;code>User(name=John, age=42)&lt;/code>&lt;/li>
&lt;li>&lt;code>copy()&lt;/code>: copy giá trị của biến và thay đổi một hoặc nhiều fields. Sẽ nói rõ hơn ở &lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#NamedArguments">7. Named arguments&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="DefaultValues">6. Default values&lt;/h3>
&lt;p>&lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> hỗ trợ &lt;code>default values&lt;/code> cho &lt;code>constructor&lt;/code> và &lt;code>method&lt;/code>.
Mình lấy ví dụ &lt;code>User&lt;/code> ở &lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#DataClasses">5. Data classes&lt;/a> sửa lại thành&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">data&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Tri Le&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">val&lt;/span> &lt;span class="py">age&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Int&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>khi đó ta có thể:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">trile&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// User(name=Tri Le, age=30)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">join&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Join&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// User(name=Join, age=30)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="NamedArguments">7. Named arguments&lt;/h3>
&lt;p>Tiếp tục với &lt;code>User&lt;/code> ở &lt;a href="https://trile.dev/post/2020-05-17-introduction-to-the-kotlin-language/#DefaultValues">6. Default values&lt;/a> khi kết hợp với &lt;code>named arguments&lt;/code> với &lt;code>default values&lt;/code> ta thể:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">join&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Join&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// User(name=Join, age=30)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">trile&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">age&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">30&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// User(name=Tri Le, age=30)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">val&lt;/span> &lt;span class="py">mary&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;Mary&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">16&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// User(name=Mary, age=16)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>khi này code chúng ta rất rõ nghĩa&lt;/p>
&lt;h3 id="FunctionalProgramingSupport">8. Functional programing support&lt;/h3>
&lt;p>&lt;code>Lambdas&lt;/code> là một big change đối với &lt;code>Java 8&lt;/code> và &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> lại nâng nó lên một tầm cao mới.&lt;/p>
&lt;p>Giả sử mình define một class &lt;code>Student&lt;/code> như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Student&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">surname&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">passing&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Boolean&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">averageGrade&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Double&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>từ danh sách các &lt;code>Student&lt;/code> trên mình có yêu cầu sau:&lt;/p>
&lt;pre tabindex="0">&lt;code>Lấy ra 10 sinh viên đã tốt nghiệp và có điểm trung bình lớn hơn 4.0
Ưu tiên cho những sinh viên điểm cao hơn
Thứ tự được sắp xếp theo tên sinh viên (surname rồi tới name)
&lt;/code>&lt;/pre>&lt;p>Với yêu cầu trên với &lt;code>Java&lt;/code> ta cần implement khá nhiều. Nhưng với &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> ta chỉ cần 4 line ;))&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="n">students&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">passing&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">averageGrade&lt;/span> &lt;span class="p">&amp;gt;&lt;/span> &lt;span class="m">4.0&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// get only students who are passing and with a grade point average of greater than 4.0
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">sortedBy&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">averageGrade&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="c1">// sort by the average grade
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">take&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// take first 10 students
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="n">sortedWith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">compareBy&lt;/span>&lt;span class="p">({&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">surname&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">it&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="p">}))&lt;/span> &lt;span class="c1">// sort students alphanumerically. The comparator compares surnames first, and if equal then it compares names
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Đây là ví dụ trong &lt;a href="https://www.freecodecamp.org/news/my-favorite-examples-of-functional-programming-in-kotlin-e69217b39112/">bài blog này&lt;/a>. Và nếu có thời gian mình sẽ có một bài viết chi tiết hơn nha ;))&lt;/p>
&lt;h3 id="ExtensionFunctions">9. Extension functions&lt;/h3>
&lt;p>Đây là ưu điểm mình yêu thích nhất của &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a> vì nếu có nhu cầu viết thêm &lt;code>method&lt;/code> hoặc &lt;code>properties&lt;/code> ta không cần viết sửa code, rất thích hợp cho việc tích các &lt;code>module&lt;/code>/&lt;code>lib&lt;/code> có sẵn. Hãy nhớ rằng đây chỉ là &lt;code>syntactic sugar&lt;/code> và không thật sự thay đổi class hoặc instance.&lt;/p>
&lt;p>Mình giả sử muốn viết hàm &lt;code>checkEmpty&lt;/code> cho &lt;code>String?&lt;/code> thì ca cần:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">String&lt;/span>&lt;span class="o">?.&lt;/span>&lt;span class="n">checkEmpty&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">this&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">null&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isEmpty&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">nullString&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">emptyString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">string&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nullString&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">checkEmpty&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// false
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">emptyString&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">checkEmpty&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// false
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">checkEmpty&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// true
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Tương tự ta có thể &lt;code>extension&lt;/code> luôn cả &lt;code>propertie&lt;/code>. Lưu ý ở đây &lt;code>extension propertie&lt;/code> cần phải tính từ các thuộc tính khác của &lt;code>class&lt;/code> hiện tại&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">val&lt;/span> &lt;span class="py">String&lt;/span>&lt;span class="o">?.&lt;/span>&lt;span class="n">empty&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">get&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">this&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">null&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isEmpty&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">nullString&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="p">?&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">emptyString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">val&lt;/span> &lt;span class="py">string&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nullString&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span> &lt;span class="c1">// false
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">emptyString&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span> &lt;span class="c1">// false
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">string&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">empty&lt;/span> &lt;span class="c1">// true
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="Coroutines">10. Coroutines: lightweight thread&lt;/h3>
&lt;p>Trước đây khi làm việc về mảng &lt;code>Network Programming&lt;/code> mình có làm việc khá nhiều với &lt;code>Java thread&lt;/code> và nhận thấy nó có những nhược điểm sau:&lt;/p>
&lt;ul>
&lt;li>&lt;code>Java thread&lt;/code> chiếm nhiều resource. Không có số liệu chính xác nhưng mỗi thread sẽ sử dụng 330KB với OS 32 bit và 1MB với OS 64 bit. Vì thế một process chỉ có thể tạo một số lượng giới hạn &lt;code>thread&lt;/code>&lt;/li>
&lt;li>Cần phải giải quyết vấn đề &lt;code>tranh chấp resource&lt;/code> ảnh hưởng tới hiệu năng, độ phức tạp của project/module&lt;/li>
&lt;li>Khó code, khó test, khó debug, khó trace&lt;/li>
&lt;li>Deadlock&lt;/li>
&lt;/ul>
&lt;p>Những vấn đề trên có thể được giải quyết với &lt;code>Coroutines&lt;/code>. Và chắc chắc cần phải có một loạt bài viết từ cơ bản tới nâng cao để giúp các bạn nắm vững &lt;code>Coroutines&lt;/code>.&lt;/p>
&lt;p>Trong khuôn khổ bài viết này mình sẽ ví dụ một case mà &lt;code>Java thread&lt;/code> không làm được xem như thị phạm ;))&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fun&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">runBlocking&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repeat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">100&lt;/span>&lt;span class="n">_000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="c1">// launch a lot of coroutines
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">launch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delay&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">5000L&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Đoạn code trên sẽ tạo ra &lt;strong>100K coroutines&lt;/strong> và sau 5 giây sẽ in ra dấu chấm với mỗi coroutine.
Và bạn thử implement đoạn code trên với &lt;code>Java thread&lt;/code> xem. Mình đảm bảo sẽ có lỗi &lt;code>out-of-memory&lt;/code>&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/KDRv3QggAjyo/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>&lt;strong>Update&lt;/strong>: loạt bài về &lt;a href="https://trile.dev/categories/coroutine">Kotlin Coroutine&lt;/a> nè&lt;/p>
&lt;p>&lt;strong>Kết:&lt;/strong> Mong với bài viết này sẽ giúp cho các bạn có cảm hứng để tìm hiểu về &lt;a href="https://kotlinlang.org">&lt;code>Kotlin&lt;/code>&lt;/a>. Từ đó nghiên cứu và áp dụng cho những dự án sắp tới của mình.&lt;/p></description><category domain="https://trile.dev/categories/kotlin/">Kotlin</category><category domain="https://trile.dev/tags/kotlin/">kotlin</category></item><item><title>Optimize Java Exception and benchmark</title><link>https://trile.dev/post/2020-04-25-optimize-java-exception-and-benchmark/</link><guid isPermaLink="true">https://trile.dev/post/2020-04-25-optimize-java-exception-and-benchmark/</guid><pubDate>Sat, 25 Apr 2020 16:24:15 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>In the post &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">Clean Code with Exception&lt;/a> I promised to solve the problem of making &lt;code>Exception&lt;/code> slow. So this post will go deeper into what Java will do when an &lt;code>Exception&lt;/code> is thrown and explain what a &lt;code>stack trace&lt;/code> is&amp;hellip; and from there will optimize the use of &lt;code>Exception&lt;/code>&lt;/p>
&lt;h3 id="WhatWillJavaDoWhenExceptionThrew">1. What will Java do when an Exception is thrown?&lt;/h3>
&lt;p>To clearly understand what Java does when an &lt;code>Exception&lt;/code> is thrown, let&amp;rsquo;s look at the code of the &lt;code>Throwable&lt;/code> class, the parent of &lt;code>Exception&lt;/code> ;))&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">Throwable&lt;/span> &lt;span class="kd">implements&lt;/span> &lt;span class="n">Serializable&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">//bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">cause&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="kc">null&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">toString&lt;/span>&lt;span class="o">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">cause&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fu fu fu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">public&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">getOurStackTrace&lt;/span>&lt;span class="o">().&lt;/span>&lt;span class="na">clone&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">synchronized&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getOurStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initialize stack trace field with information from
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// backtrace if this is the first call to this method
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span> &lt;span class="o">||&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">backtrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cm">/* Out of protocol state */&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stackTrace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">of&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="k">this&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">depth&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">stackTrace&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">synchronized&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">||&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">backtrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="cm">/* Out of protocol state */&lt;/span> &lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stackTrace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">native&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">dummy&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fe fe fe
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The above code shows us that all the &lt;code>public constructors&lt;/code> of &lt;code>Throwable&lt;/code> call the &lt;code>fillInStackTrace()&lt;/code> function. So what does this function do and why do we need to call it? To get the answer, let&amp;rsquo;s go to the next section&lt;/p>
&lt;h3 id="StackTraceWhy">2. What is a stack trace? Why do we need to use it?&lt;/h3>
&lt;p>Suppose we have the following code and try to run it&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">Junk&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">[])&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">HighLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">printStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">a&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">HighLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">MidLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">HighLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">b&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">MidLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">c&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">MidLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">LowLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MidLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">d&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">LowLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">e&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">LowLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">LowLevelException&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">HighLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HighLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">);&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">MidLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MidLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">);&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">LowLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The result will be the following error:&lt;/p>
&lt;pre tabindex="0">&lt;code>HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more
Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
&lt;/code>&lt;/pre>&lt;p>Analyzing the above error message, we have the following interpretation:&lt;/p>
&lt;ul>
&lt;li>An exception &lt;code>HighLevelException&lt;/code> was thrown. The cause of &lt;code>HighLevelException&lt;/code> is &lt;code>MidLevelException&lt;/code> and the cause of &lt;code>MidLevelException&lt;/code> is &lt;code>LowLevelException&lt;/code>&lt;/li>
&lt;li>&lt;code>HighLevelException&lt;/code> appears in class &lt;code>Junk&lt;/code> method &lt;code>a&lt;/code> file &lt;code>Junk.java&lt;/code> line 13 and method &lt;code>a&lt;/code> is called from class &lt;code>Junk&lt;/code> method &lt;code>main&lt;/code> file &lt;code>Junk.java&lt;/code> line 4&lt;/li>
&lt;li>&lt;code>MidLevelException&lt;/code> appears in class &lt;code>Junk&lt;/code> method &lt;code>c&lt;/code> file &lt;code>Junk.java&lt;/code> line 23, method &lt;code>c&lt;/code> is called from class &lt;code>Junk&lt;/code> method &lt;code>b&lt;/code> file &lt;code>Junk.java&lt;/code> line 17 and method &lt;code>b&lt;/code> is called from class &lt;code>Junk&lt;/code> method &lt;code>a&lt;/code> file &lt;code>Junk.java&lt;/code> line 11&lt;/li>
&lt;li>&lt;code>LowLevelException&lt;/code> is similar to &lt;code>MidLevelException&lt;/code> and &lt;code>HighLevelException&lt;/code> but I also have a headache. Of course, if there is an error and need to trace, I still have to do it ;))&lt;/li>
&lt;/ul>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/13Q9MdRZh4UZVu/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>And from the above analysis, we can redraw the flow where the exception is thrown
how it looks like:&lt;/p>
&lt;p>&lt;img src="https://trile.dev/diagram/stack-trace.svg" alt="Stack trace">&lt;/p>
&lt;p>My image above can also be considered a representation of &lt;code>stack trace&lt;/code>. &lt;strong>To be more specific, &lt;code>stack trace&lt;/code> is an ordered list of function calls and is arranged in the order of calls from the most recent to the first call&lt;/strong>. It is very useful in analyzing, finding the cause and from there deciding whether to fix the error or not.&lt;/p>
&lt;p>Back to the question in &lt;strong>#1&lt;/strong>. Then we have the answer. The &lt;code>fillInStackTrace()&lt;/code> function is to &lt;code>collect stack trace&lt;/code> and it is very useful, isn&amp;rsquo;t it 🤟&lt;/p>
&lt;h3 id="CollectStackTrace">3. Collect stack trace fast or slow?&lt;/h3>
&lt;p>The answer is &lt;strong>very slow&lt;/strong> and to see how slow you can clone &lt;a href="https://gitlab.com/thanhtrixx/optimize-java-exception">this repo&lt;/a>. If you do variables, see &lt;strong>#5&lt;/strong>.&lt;/p>
&lt;h3 id="DisableCollectStackTrace">4. Disable collect stack trace and optimize&lt;/h3>
&lt;p>I rewrote &lt;code>NSTException&lt;/code> and simplified the 2 functions &lt;code>getStackTrace()&lt;/code> and &lt;code>fillInStackTrace()&lt;/code> as the following code:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">NSTException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kd">final&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="n">EMPTY_STACK_TRACE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">NSTException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">EMPTY_STACK_TRACE&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now when &lt;code>NSTException&lt;/code> is initialized, it will not &lt;code>collect stack trace&lt;/code> anymore. Let&amp;rsquo;s see the results.&lt;/p>
&lt;h3 id="Benchmark">5. Benchmark&lt;/h3>
&lt;p>I will explain a little bit about how to benchmark. I have 3 methods &lt;code>callNotThrowException&lt;/code>, &lt;code>callToThrowException&lt;/code> and &lt;code>callToThrowNSTException&lt;/code> used to simulate the following situations:&lt;/p>
&lt;ul>
&lt;li>&lt;code>callNotThrowException&lt;/code>: normal situation, no &lt;code>Exception&lt;/code> is thrown&lt;/li>
&lt;li>&lt;code>callToThrowException&lt;/code>: situation where &lt;code>Exception&lt;/code> is thrown&lt;/li>
&lt;li>&lt;code>callToThrowNSTException&lt;/code>: situation where &lt;code>NSTException&lt;/code> is thrown. &lt;code>NSTException&lt;/code> stands for &lt;em>No Stack Trace Exception&lt;/em>, a custom exception I rewrote, turning off stack trace collection to increase performance&lt;/li>
&lt;/ul>
&lt;p>Due to differences in configuration, OS, Java version&amp;hellip; the results may vary. And here are the results from my machine:&lt;/p>
&lt;pre tabindex="0">&lt;code>Benchmark (param) Mode Cnt Score Error Units
Jmh.callNotThrowException 1 thrpt 25 80504640.048 ± 15390305.644 ops/s
Jmh.callToThrowException 1 thrpt 25 703653.862 ± 58119.745 ops/s
Jmh.callToThrowNSTException 1 thrpt 25 41387559.456 ± 6619635.038 ops/s
&lt;/code>&lt;/pre>&lt;p>We note that the 2 results of &lt;code>Jmh.callNotThrowException&lt;/code> and &lt;code>Jmh.callToThrowException&lt;/code> are &lt;code>80504640.048&lt;/code> and &lt;code>703653.862&lt;/code> (ignoring the ± error) then 80504640.048 / 703653.862 = &lt;strong>114&lt;/strong> is a very large number.&lt;/p>
&lt;p>&lt;strong>Conclusion:&lt;/strong> By using &lt;code>NSTException&lt;/code> to turn off &lt;code>collect stack trace&lt;/code>, we have the following advantages:&lt;/p>
&lt;ul>
&lt;li>Speed up the application and use memory more efficiently&lt;/li>
&lt;li>Make the method signature easier to understand&lt;/li>
&lt;li>External control code is easier to understand when separating business code and error handling, I will also have a post about this part&lt;/li>
&lt;/ul>
&lt;p>But there is also a disadvantage that there is no stack trace, from which tracing errors will be difficult. Please watch the next post to solve it.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video style="height: 200px" autoplay loop muted playsinline src="https://media.giphy.com/media/RLW9YEaSBfBMt79fm4/giphy.mp4">&lt;/video>
&lt;/div></description><category domain="https://trile.dev/categories/clean-code/">Clean Code</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/exception/">exception</category><category domain="https://trile.dev/tags/optimize/">optimize</category><category domain="https://trile.dev/tags/performance/">performance</category><category domain="https://trile.dev/tags/jmh/">jmh</category></item><item><title>Optimize Java Exception and benchmark</title><link>https://trile.dev/post/2020-04-25-optimize-java-exception-and-benchmark.vn/</link><guid isPermaLink="true">https://trile.dev/post/2020-04-25-optimize-java-exception-and-benchmark.vn/</guid><pubDate>Sat, 25 Apr 2020 16:24:15 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Ở bài &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">Clean Code with Exception&lt;/a> mình có hứa sẽ giải quyết vấn đề làm &lt;code>Exception&lt;/code> chậm. Vì thế bài này sẽ đi vào sâu hơn việc Java sẽ làm gì khi có 1 &lt;code>Exception&lt;/code> được throw ra và giải thích &lt;code>stack trace&lt;/code> là gì&amp;hellip; và từ đó sẽ tối ưu việc sử dụng &lt;code>Exception&lt;/code>&lt;/p>
&lt;h3 id="WhatWillJavaDoWhenExceptionThrew">1. Java sẽ làm gì khi có 1 Exception được throw ra?&lt;/h3>
&lt;p>Để hiểu rõ Java làm gì khi có 1 &lt;code>Exception&lt;/code> được throw ra thì ta hãy vào xem code của class &lt;code>Throwable&lt;/code> cha của &lt;code>Exception&lt;/code> hen ;))&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">Throwable&lt;/span> &lt;span class="kd">implements&lt;/span> &lt;span class="n">Serializable&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">//bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">cause&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">Throwable&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">detailMessage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="kc">null&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">toString&lt;/span>&lt;span class="o">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">cause&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fu fu fu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kd">public&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">getOurStackTrace&lt;/span>&lt;span class="o">().&lt;/span>&lt;span class="na">clone&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">synchronized&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getOurStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initialize stack trace field with information from
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// backtrace if this is the first call to this method
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span> &lt;span class="o">||&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">backtrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="cm">/* Out of protocol state */&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stackTrace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">of&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="k">this&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">depth&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">stackTrace&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">synchronized&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">stackTrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">||&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">backtrace&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="cm">/* Out of protocol state */&lt;/span> &lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fillInStackTrace&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stackTrace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UNASSIGNED_STACK&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">native&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">dummy&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fe fe fe
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Đoạn code trên cho ta thấy tất cả các &lt;code>public constructor&lt;/code> của &lt;code>Throwable&lt;/code> đều gọi hàm &lt;code>fillInStackTrace()&lt;/code>. Vậy hàm này làm gì và tại sao cần gọi nó? Để có được câu trả lời ta đi vào phần tiếp theo&lt;/p>
&lt;h3 id="StackTraceWhy">2. Stack trace là gì? Vì sao cần dùng nó?&lt;/h3>
&lt;p>Giả sử ta có đoạn code sau và thử chạy nó&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">Junk&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">[])&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">HighLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">printStackTrace&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">a&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">HighLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">MidLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">HighLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">b&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">MidLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">c&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">c&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">MidLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">d&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">LowLevelException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MidLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">d&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">LowLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">e&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">e&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">LowLevelException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">LowLevelException&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">HighLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HighLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">);&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">MidLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MidLevelException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Throwable&lt;/span> &lt;span class="n">cause&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">cause&lt;/span>&lt;span class="o">);&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">LowLevelException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Kết quả sẽ có lỗi sau:&lt;/p>
&lt;pre tabindex="0">&lt;code>HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more
Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
&lt;/code>&lt;/pre>&lt;p>Phân tích message lỗi trên ta có diễn dịch lại sau:&lt;/p>
&lt;ul>
&lt;li>Có exception &lt;code>HighLevelException&lt;/code> được throw ra. Nguyên nhân của &lt;code>HighLevelException&lt;/code> là &lt;code>MidLevelException&lt;/code> và nguyên nhân của &lt;code>MidLevelException&lt;/code> là &lt;code>LowLevelException&lt;/code>&lt;/li>
&lt;li>&lt;code>HighLevelException&lt;/code> xuất hiện ở class &lt;code>Junk&lt;/code> method &lt;code>a&lt;/code> file &lt;code>Junk.java&lt;/code> dòng thứ 13 và method &lt;code>a&lt;/code> được gọi từ class &lt;code>Junk&lt;/code> method &lt;code>main&lt;/code> file &lt;code>Junk.java&lt;/code> dòng thứ 4&lt;/li>
&lt;li>&lt;code>MidLevelException&lt;/code> xuất hiện ở class &lt;code>Junk&lt;/code> method &lt;code>c&lt;/code> file &lt;code>Junk.java&lt;/code> dòng thứ 23, method &lt;code>c&lt;/code> được gọi từ class &lt;code>Junk&lt;/code> method &lt;code>b&lt;/code> file &lt;code>Junk.java&lt;/code> dòng thứ 17 và method &lt;code>b&lt;/code> được gọi từ class &lt;code>Junk&lt;/code> method &lt;code>a&lt;/code> file &lt;code>Junk.java&lt;/code> dòng thứ 11&lt;/li>
&lt;li>&lt;code>LowLevelException&lt;/code> thì tương tự như với &lt;code>MidLevelException&lt;/code> và &lt;code>HighLevelException&lt;/code> chứ mình cũng hơi đau đầu rồi đó. Tất nhiên nếu có lỗi và cần trace thì vẫn phải làm ;))&lt;/li>
&lt;/ul>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/13Q9MdRZh4UZVu/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Và từ phân tích trên ta có thể vẻ lại flow mà exception bị throw ra như thế nào:&lt;/p>
&lt;p>&lt;img src="https://trile.dev/diagram/stack-trace.svg" alt="Stack trace">&lt;/p>
&lt;p>Hình vẻ trên của mình cũng có thể coi là một biểu diễn của &lt;code>stack trace&lt;/code>. &lt;strong>Nói rõ hơn &lt;code>stack trace&lt;/code> là một danh sách có thứ tự của các lời gọi hàm và được sắp xếp theo thứ tự gọi từ các lời gọi gần đây nhất tới lời gọi đầu tiên&lt;/strong>. Nó rất hữu ích trong việc phân tích, tìm nguyên nhân và từ đó ra quyết định có cần fix lỗi hay không.&lt;/p>
&lt;p>Quay lại câu hỏi ở &lt;strong>#1&lt;/strong>. Thì ta đã có câu trả lời. Hàm &lt;code>fillInStackTrace()&lt;/code> là đi &lt;code>collect stack trace&lt;/code> và nó rất hữu ích phải không nào 🤟&lt;/p>
&lt;h3 id="CollectStackTrace">3. Collect stack trace nhanh hay chậm?&lt;/h3>
&lt;p>Câu trả lời là &lt;strong>rất chậm&lt;/strong> và để biết chậm như thế nào bạn có thể clone &lt;a href="https://gitlab.com/thanhtrixx/optimize-java-exception">repo này&lt;/a>. Còn nếu bạn làm biến thì xem &lt;strong>#5&lt;/strong> nha.&lt;/p>
&lt;h3 id="DisableCollectStackTrace">4. Tắt collect stack trace và optimize&lt;/h3>
&lt;p>Mình có viết lại &lt;code>NSTException&lt;/code> và đơn giản hoá 2 hàm &lt;code>getStackTrace()&lt;/code> và &lt;code>fillInStackTrace()&lt;/code> như đoạn code sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">NSTException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kd">final&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="n">EMPTY_STACK_TRACE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">NSTException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">StackTraceElement&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="nf">getStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">EMPTY_STACK_TRACE&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">Throwable&lt;/span> &lt;span class="nf">fillInStackTrace&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lúc này khi &lt;code>NSTException&lt;/code> được khởi tạo nó sẽ không &lt;code>collect stack trace&lt;/code> nữa. Cùng xem thành quả như thế nào nhé.&lt;/p>
&lt;h3 id="Benchmark">5. Benchmark&lt;/h3>
&lt;p>Mình giải thích chút xíu về cách thức benchmark. Mình có 3 method &lt;code>callNotThrowException&lt;/code>, &lt;code>callToThrowException&lt;/code> và &lt;code>callToThrowNSTException&lt;/code> dùng giả lập các tình huống:&lt;/p>
&lt;ul>
&lt;li>&lt;code>callNotThrowException&lt;/code>: tình huống bình thường, không có &lt;code>Exception&lt;/code> này được throw ra&lt;/li>
&lt;li>&lt;code>callToThrowException&lt;/code>: tình huống &lt;code>Exception&lt;/code> được throw ra&lt;/li>
&lt;li>&lt;code>callToThrowNSTException&lt;/code>: tình huống &lt;code>NSTException&lt;/code> được throw ra. &lt;code>NSTException&lt;/code> viết tắt của &lt;em>No Stack Trace Exception&lt;/em> là một custom exception mình viết lại, tắt collection stack trace để tăng hiệu năng&lt;/li>
&lt;/ul>
&lt;p>Do khác nhau về cấu hình, OS, Java version&amp;hellip; nên kết quả có thể khác nhau. Và đây là kết quả từ máy mình:&lt;/p>
&lt;pre tabindex="0">&lt;code>Benchmark (param) Mode Cnt Score Error Units
Jmh.callNotThrowException 1 thrpt 25 80504640.048 ± 15390305.644 ops/s
Jmh.callToThrowException 1 thrpt 25 703653.862 ± 58119.745 ops/s
Jmh.callToThrowNSTException 1 thrpt 25 41387559.456 ± 6619635.038 ops/s
&lt;/code>&lt;/pre>&lt;p>Ta chú ý 2 kết quả của &lt;code>Jmh.callNotThrowException&lt;/code> và &lt;code>Jmh.callToThrowException&lt;/code> lần lượt là &lt;code>80504640.048&lt;/code> và &lt;code>703653.862&lt;/code> (bỏ qua sai số ±) thì 80504640.048 / 703653.862 = &lt;strong>114&lt;/strong> quả là một con số rất lớn.&lt;/p>
&lt;p>&lt;strong>Kết luận:&lt;/strong> bằng việc sử dụng &lt;code>NSTException&lt;/code> để tắt &lt;code>collect stack trace&lt;/code> giúp ta có những ưu điểm sau:&lt;/p>
&lt;ul>
&lt;li>Tăng tốc ứng dụng và sử dụng bộ nhớ hiệu quả hơn&lt;/li>
&lt;li>Làm cho method signature dễ hiểu&lt;/li>
&lt;li>Code control bên ngoài dễ hiểu hơn khi tách biệt code bussiness và handle lỗi, mình cũng sẽ có bài về phần này&lt;/li>
&lt;/ul>
&lt;p>Nhưng kèm đó cũng có nhược điểm là không còn stack trace, từ đó việc trace lỗi sẽ khó khăn. Mời các bạn đón xem bài tiếp theo để giải quyết.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video style="height: 200px" autoplay loop muted playsinline src="https://media.giphy.com/media/RLW9YEaSBfBMt79fm4/giphy.mp4">&lt;/video>
&lt;/div></description><category domain="https://trile.dev/categories/clean-code/">Clean Code</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/exception/">exception</category><category domain="https://trile.dev/tags/optimize/">optimize</category><category domain="https://trile.dev/tags/performance/">performance</category><category domain="https://trile.dev/tags/jmh/">jmh</category></item><item><title>Try/Catch Explain</title><link>https://trile.dev/post/2020-04-22-try-catch-explain/</link><guid isPermaLink="true">https://trile.dev/post/2020-04-22-try-catch-explain/</guid><pubDate>Wed, 22 Apr 2020 00:01:01 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Tiếp tục loạt bài về &lt;code>Exception&lt;/code> &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">&lt;code>Clean Code with Exception&lt;/code>&lt;/a>. Bài này mình sẽ nói nói rõ hơn về &lt;code>try/catch&lt;/code> và minh oan cho &lt;code>try/catch&lt;/code> khi bị chê là làm cho performance của chương trình chậm lại.&lt;/p>
&lt;p>Đầu tiên mình xin giải thích &lt;code>try&lt;/code> là gì và &lt;code>catch&lt;/code> là gì:&lt;/p>
&lt;ul>
&lt;li>&lt;code>try&lt;/code> là một từ khoá của Java để khai báo một đoạn code mà trong đó khi &lt;code>throws&lt;/code> ra một &lt;code>Throwable&lt;/code> sẽ được xử lý bởi đoạn &lt;code>catch&lt;/code> khai báo sau đó.&lt;/li>
&lt;li>&lt;code>catch&lt;/code> là một từ khoá của Java để khai báo một đoạn code sẽ được thực thi nếu bắt được một &lt;code>Throwable&lt;/code> được &lt;code>throws&lt;/code> ra bởi các đoạn code nằm trong &lt;code>try&lt;/code> khai báo trước đó.&lt;/li>
&lt;/ul>
&lt;p>&lt;code>try&lt;/code> và &lt;code>catch&lt;/code> là một cặp luôn luôn đi cùng nhau.&lt;/p>
&lt;h3 id="UseCases">1. Các tình huống sử dụng&lt;/h3>
&lt;ul>
&lt;li>Bắt tất cả các &lt;code>Exception&lt;/code>&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fu fu fu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>Bắt các &lt;code>IOException&lt;/code> trước và &lt;code>Exception&lt;/code> sau&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">IOException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fu fu fu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fe fe fe
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lưu ý là các &lt;code>Exception&lt;/code> con nên nằm trước, các &lt;code>Exception&lt;/code> cha nên nằm sau.&lt;/p>
&lt;ul>
&lt;li>Bắt các &lt;code>IOException&lt;/code> và &lt;code>RuntimeException&lt;/code> và xử lý trong cùng một statement&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">IOException&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">RuntimeException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fu fu fu
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// fe fe fe
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="CheckedAndUnCheckedExceptions">2. Checked và UnChecked Exceptions&lt;/h3>
&lt;p>Khi dùng Java một trong những điểm làm mình không thích được ở nó là &lt;code>Checked Exception&lt;/code> khi mà nó bắt buộc mình phải handle &lt;code>Exception&lt;/code>. Nếu ta cố ý không &lt;code>try/catch&lt;/code> cho đoạn code &lt;code>throws&lt;/code> ra &lt;code>Checked Exception&lt;/code> thì compiler sẽ báo lỗi và không thể build được dù có thể &lt;code>Checked Exception&lt;/code> sẽ không bao giờ xảy ra. Điều này dẫn đến code dư thừa không cần thiết.&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/QABIA4v1Y1v8Y/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Mình lấy ví dụ như trường hợp&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">Cipher&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getInstance&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;AES/CBC/PKCS5Padding&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>hoặc&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataToEncrypt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getBytes&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;UTF-8&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>sẽ luôn luôn cần phải hand exception do signature của nó khai báo sẽ &lt;code>throws&lt;/code> ra các &lt;code>Checked Exception&lt;/code> cho dù mình đảm bảo code trên không bao giờ bị &lt;code>Exception&lt;/code>. Và khi đó code mình sẽ đại loại thế này&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">byte&lt;/span> &lt;span class="o">[]&lt;/span> &lt;span class="n">bytes&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bytes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataToEncrypt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getBytes&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;UTF-8&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">UnsupportedEncodingException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// f*ck
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>hoặc&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">byte&lt;/span> &lt;span class="o">[]&lt;/span> &lt;span class="n">bytes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataToEncrypt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getBytes&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;UTF-8&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">UnsupportedEncodingException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// f*ck
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Đáng lẽ ra nó chỉ đơn giản như vầy thôi&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">byte&lt;/span> &lt;span class="o">[]&lt;/span> &lt;span class="n">bytes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataToEncrypt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getBytes&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;UTF-8&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// bla bla bla
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/13Q9MdRZh4UZVu/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Nói lang mang quá rồi. Vậy làm thế nào để xác định một &lt;code>Checked Exception&lt;/code>? Các bạn nhìn hình sau nhé:&lt;/p>
&lt;p>&lt;img src="https://trile.dev/img/exception-hierarchy.png" alt="Exception hierarchy">&lt;/p>
&lt;p>Mấy class màu xanh và con của tụi nó là &lt;code>UnChecked Exception&lt;/code> còn mấy cái màu đỏ hay là những class con của &lt;code>Exception&lt;/code> nhưng không phải &lt;code>RuntimeException&lt;/code> là &lt;code>Checked Exception&lt;/code> (giải thích rối não vlc :D)&lt;/p>
&lt;p>Có một điểm khá thú vị là &lt;code>.NET&lt;/code> và các &lt;code>JVM language&lt;/code> như &lt;code>Kotlin&lt;/code>, &lt;code>Groovy&lt;/code>, &lt;code>Scala&lt;/code> đều không có khái niệm &lt;code>Checked Exception&lt;/code> hay nói cách khác người dùng cần tự biết mà handle &lt;code>Exception&lt;/code> thay vì bị bắt buộc handle. Vậy là anh cả &lt;code>Java&lt;/code> đã bị đàn em cho ra rìa rồi ;))&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/d1E1msx7Yw5Ne1Fe/giphy.mp4">&lt;/video>
&lt;/div>
&lt;h3 id="TryPerformanceImpact">3. Try performance impact&lt;/h3>
&lt;p>Mình thường được các &amp;ldquo;đại ka&amp;rdquo; có kinh nghiệm chỉ giáo là không nên dùng &lt;code>Exception&lt;/code> với lý do là sẽ làm hệ thống chạy chậm lại. Mà thay vào đó có 2 cách để giải quyết:&lt;/p>
&lt;ul>
&lt;li>Nên trả về thêm thông tin mã lỗi và mình sẽ gặp tình huống giống như bài này &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">&lt;code>Clean Code with Exception&lt;/code>&lt;/a>.&lt;/li>
&lt;li>Gộp tất cả các thông tin xử lý vào một class info. Class info trên sẽ được truyền qua các method xử lý. Khi có lỗi gì thì method đang xử lý sẽ set thông tin vào class info này và cái phương thức gọi cần phải check lại xem có lỗi hay không. Code smell quá ;((&lt;/li>
&lt;/ul>
&lt;p>Haizz! Đọc tới đây chắc có bạn sẽ nói &lt;strong>đây là cái giá của việc muốn code chạy nhanh&lt;/strong>. Nhưng thật sự không phải thế. Bản chất &lt;code>try&lt;/code> không làm chậm code mà nó chỉ khai báo rằng những đoạn code nằm trong nó nếu có lỗi sẽ được phần code trong &lt;code>catch&lt;/code> dưới nó xử lý. Bạn có thể xem kỹ hơn ở &lt;a href="https://stackoverflow.com/questions/16451777/is-it-expensive-to-use-try-catch-blocks-even-if-an-exception-is-never-thrown">đây&lt;/a> nhé.&lt;/p>
&lt;p>Nói thế thì do đâu mà khi 1 &lt;code>Exception&lt;/code> xảy ra làm chương trình chạy chậm lại?&lt;/p>
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/7K3p2z8Hh9QOI/giphy.mp4">&lt;/video>
&lt;/div>
&lt;p>Câu trả lời là do &lt;strong>quá trình collect &lt;code>stacktrace&lt;/code>&lt;/strong> làm chậm chương trình. Và mình hứa sẽ có một bài hướng dẫn các bạn giải quyết vấn đề này!&lt;/p>
&lt;p>&lt;strong>Update&lt;/strong>: bài mình hứa ở đây nhé &lt;a href="https://trile.dev/post/2020-04-25-optimize-java-exception-and-benchmark">Optimize Java Exception and benchmark&lt;/a> :)&lt;/p></description><category domain="https://trile.dev/categories/clean-code/">Clean Code</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/try-catch/">try-catch</category><category domain="https://trile.dev/tags/exception/">exception</category><category domain="https://trile.dev/tags/explain/">explain</category></item><item><title>Custom Exception</title><link>https://trile.dev/post/2020-03-15-custom-exception/</link><guid isPermaLink="true">https://trile.dev/post/2020-03-15-custom-exception/</guid><pubDate>Sun, 15 Mar 2020 00:33:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Ở bài &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">&lt;code>Clean Code with Exception&lt;/code>&lt;/a> mình có nói về cách dùng &lt;code>Exception&lt;/code> để giúp code được đẹp hơn nhưng quả thật thiếu sót khi không có một ví dụ hoàn chỉnh cũng như hướng dẫn sử dụng &lt;code>custom Exception&lt;/code> để giúp cho &lt;code>Exception&lt;/code> rõ nghĩa và cung cấp nhiều thông tin hơn.&lt;/p>
&lt;p>Yêu cầu cũng giống như bài &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">Clean Code with Exception&lt;/a>. Mình copy qua đây cho tiện khỏi phải xem lại ;))&lt;/p>
&lt;p>Viết chương trình tính và chuyển lương cho nhân viên công ty. Từ yêu cầu này cần làm 3 việc sau:&lt;/p>
&lt;ol>
&lt;li>Tính lương cho nhân viên&lt;/li>
&lt;li>Chuyển lương tới nhân viên&lt;/li>
&lt;li>Điều phối việc tính và chuyển lương&lt;/li>
&lt;/ol>
&lt;p>#1 mình đã làm rồi ở bài &lt;a href="https://trile.dev/post/2020-01-21-clean-code-with-exception">Clean Code with Exception&lt;/a> nhưng nếu xét tổng quát thì #3 cần biết loại lỗi ở #1 và #2. Giả sử #1 cần yêu cần người dùng nhập lại và dừng chương trình, còn #2 thì có thể retry (công ty chuyển lương qua 2 ngân hàng VCB và VTB, VCB lỗi thì thử VTB) ;))&lt;/p>
&lt;h3 id="SalaryCalculator">1. Tính lương cho nhân viên&lt;/h3>
&lt;p>Từ phân tích trên Exception sẽ không thể đáp ứng yêu cầu. Ta cần custom lại Exception&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">SalaryException&lt;/span> &lt;span class="kd">extends&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="n">ErrorType&lt;/span> &lt;span class="n">codeType&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="nf">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">ErrorType&lt;/span> &lt;span class="n">errorType&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">String&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">super&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">codeType&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">errorType&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">ErrorType&lt;/span> &lt;span class="nf">getCodeType&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">codeType&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Với enum define các loại lỗi:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">enum&lt;/span> &lt;span class="n">ErrorType&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UNKNOWN_ERROR&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CALC_SALARY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TRANSFER_MONEY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TRANSFER_MONEY_NOT_ENOUGH_MONEY&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Từ đây ta sửa lại hàm tính lương một chút:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">SalaryCalculator&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">CALC_SALARY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s">&amp;#34;WorkingDay less than or equal zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">salaryPerDay&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">CALC_SALARY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s">&amp;#34;SalaryPerDay less than or equal zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">workingDay&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="TransferMoney">2. Chuyển lương tới nhân viên&lt;/h3>
&lt;p>Bây giờ ta viết những class hỗ trợ chuyển tiền. Giả sử ta tích hợp với 2 ngân hàng VietcomBank và VietinBank. 2 ngân hàng này sẽ phải implement bởi interface&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">interface&lt;/span> &lt;span class="nc">Bank&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">transferMoney&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">default&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">checkTransferParams&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">accountNo&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">length&lt;/span>&lt;span class="o">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">TRANSFER_MONEY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s">&amp;#34;AccountNo null or empty&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">TRANSFER_MONEY_PARAMS_INVALID&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s">&amp;#34;Amount less than or equal zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Mình có implement thêm hành kiểm tra tham số cho việc chuyển tiền qua hàm &lt;code>checkTransferParams&lt;/code>&lt;/p>
&lt;p>Implement cho VietcomBank&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">VietcomBank&lt;/span> &lt;span class="kd">implements&lt;/span> &lt;span class="n">Bank&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">transferMoney&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">checkTransferParams&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">10_000_000&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryException&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">TRANSFER_MONEY_NOT_ENOUGH_MONEY&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="s">&amp;#34;VCB only support transfer amount less than 10M&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;VCB transfer success&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Để giả lập lỗi ngân hàng. Mình sẽ cho VietcomBank bị lỗi khi số tiền lớn hơn 10M&lt;/p>
&lt;p>Tương tự với VietinBank nhưng không lỗi&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">VietinBank&lt;/span> &lt;span class="kd">implements&lt;/span> &lt;span class="n">Bank&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">transferMoney&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">checkTransferParams&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;VTB transfer success&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="SalaryTransfer">3. Điều phối việc tính và chuyển lương&lt;/h3>
&lt;p>Và cuối cùng là #3 điều phối việc tính và chuyển lương&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">SalaryTransfer&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">final&lt;/span> &lt;span class="n">MoneyTransfer&lt;/span> &lt;span class="n">moneyTransfer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MoneyTransfer&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kd">final&lt;/span> &lt;span class="n">SalaryCalculator&lt;/span> &lt;span class="n">salaryCalculator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryCalculator&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">salaryTransfer&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">String&lt;/span> &lt;span class="n">accountNo&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">SalaryException&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">salary&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">salaryCalculator&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">moneyTransfer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">transferMoney&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">accountNo&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">salary&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;Transfer Salary success&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SalaryTransfer&lt;/span> &lt;span class="n">salaryTransfer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryTransfer&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">salaryTransfer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">salaryTransfer&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Integer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">parseInt&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">]),&lt;/span> &lt;span class="n">Integer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">parseInt&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">args&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">]),&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">NumberFormatException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;Parse int error &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getMessage&lt;/span>&lt;span class="o">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">SalaryException&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getMessage&lt;/span>&lt;span class="o">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ở đây mình viết luôn hàm &lt;code>main&lt;/code> để thử chạy luôn. Các bạn có thể xem full ví dụ ở &lt;a href="https://gitlab.com/thanhtrixx/trile-dev-sample/-/tree/master/custom-exception">repo này&lt;/a>&lt;/p>
&lt;h3 id="BuildAndTest">4. Build và test&lt;/h3>
&lt;p>Ta chạy command sau để build&lt;/p>
&lt;pre tabindex="0">&lt;code>./gradlew clean build
&lt;/code>&lt;/pre>&lt;p>và test thử:&lt;/p>
&lt;pre tabindex="0">&lt;code>java -cp build/libs/*.jar dev.trile.customexception.SalaryTransfer 11 1000000 EM1
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>Transfer 11000000 to EM1
VCB only support transfer amount less than 10M
Retry with VTB
VTB transfer success
Transfer Salary success
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>java -cp build/libs/*.jar dev.trile.customexception.SalaryTransfer -1 1000000 EM1
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>WorkingDay less than or equal zero
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>java -cp build/libs/*.jar dev.trile.customexception.SalaryTransfer 10 -1000000 EM1
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>SalaryPerDay less than or equal zero
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>java -cp build/libs/*.jar dev.trile.customexception.SalaryTransfer 15 1000000 EM1
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>Transfer 15000000 to EM1
VCB only support transfer amount less than 10M
Retry with VTB
VTB transfer success
Transfer Salary success
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Kết luận:&lt;/strong> bằng việc sử dụng &lt;code>custom Exception&lt;/code> giúp code trở nên rõ ràng và nhất quán trong việc xử lý nếu có lỗi xảy ra&lt;/p>
&lt;ul>
&lt;li>Trường hợp thông thường khi có 1 &lt;code>Exception&lt;/code> được throw ra thì flow sẽ bị break như ở hàm &lt;code>calcSalary&lt;/code> và &lt;code>salaryTransfer&lt;/code>&lt;/li>
&lt;li>Trường hợp ta có hướng xử lý cho một &lt;code>Exception&lt;/code> cụ thể thì ta sẽ thực hiện &lt;code>try/catch&lt;/code> và handle như ở &lt;code>MoneyTransfer.moneyTransfer&lt;/code>&lt;/li>
&lt;/ul></description><category domain="https://trile.dev/categories/clean-code/">Clean Code</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/exception/">exception</category></item><item><title>Clean Code with Exception</title><link>https://trile.dev/post/2020-01-21-clean-code-with-exception/</link><guid isPermaLink="true">https://trile.dev/post/2020-01-21-clean-code-with-exception/</guid><pubDate>Tue, 21 Jan 2020 08:36:15 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Không biết anh em lúc mới làm quen thế nào chứ lúc mình học Java thì cái làm mình cảm thấy khó chịu nhất là &lt;code>Exception&lt;/code>. Cứ hở một chút là bắt &lt;code>try/catch&lt;/code> (sẽ có một bài viết chi tiết hơn về vấn đề này) và làm cho code mình trở nên cực kỳ kinh khủng. Nhưng sau thời gian tìm hiểu thì mình nhận thấy đây là một thứ khá hay ho trong lập trình.&lt;/p>
&lt;p>Vì sao à? Đọc tiếp nhé :v&lt;/p>
&lt;p>Giả sử team mình nhận được một yêu cầu từ síp lớn là viết chương trình tính và chuyển lương cho nhân viên công ty. Từ yêu cầu này síp mình phân tích cần làm 3 việc sau:&lt;/p>
&lt;ol>
&lt;li>Tính lương cho nhân viên -&amp;gt; mình làm&lt;/li>
&lt;li>Chuyển lương tới nhân viên -&amp;gt; bạn ngồi kế bên làm&lt;/li>
&lt;li>Điều phối việc tính và chuyển lương -&amp;gt; síp làm&lt;/li>
&lt;/ol>
&lt;p>Thông số truyền vào số ngày làm việc trong tháng và tiền lương trong một ngày. Quá đơn giản phải k ;)&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">pubic&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">workingDay&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Sau khi đưa síp review thì bị la! &lt;code>workingDay&lt;/code> và &lt;code>salaryPerDay&lt;/code> âm thì như thế nào?
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/tJeGZumxDB01q/giphy.mp4">&lt;/video>
&lt;/div>
Mình nhanh nhẩu trả lời: Thì cái thằng gọi bên ngoài phải handle chứ!&lt;br>
Ổng phản damage: Tao là thằng gọi nè, chú phải tự validate chứ! Đừng quá tin anh. Vừa nói ổng vừa mỉm một nụ cười bí ẩn :~&lt;/p>
&lt;p>Thế là hậm hụi ngồi viết lại :(.&lt;/p>
&lt;p>Từ yêu cầu của síp ta cần trả về thông tin để síp có thể biết lúc nào thông tin nhập bị lỗi, lỗi cụ thể là gì và kết quả lương nếu không có lỗi.
Vấn đề bắt đầu từ đây. Từ signature của hàm dễ hiểu nhìn vào là hiểu ngay. Giờ phải thêm thông tin để hàm gọi biết param truyền vào đúng valid không nên mình trả về là một class chứa lương và mã lỗi, mã lỗi là 0 tương ứng không có lỗi&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">class&lt;/span> &lt;span class="nc">SalaryResult&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salary&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">errorCode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// getters and settters
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pubic&lt;/span> &lt;span class="n">SalaryResult&lt;/span> &lt;span class="nf">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SalaryResult&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SalaryResult&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">setErrorCode&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">salaryPerDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">setErrorCode&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">setSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Síp review thì lại bắt sửa tiếp. Lý do vì ổng phải điều phối việc tính lương và chuyển lương. Handle mã lỗi thôi thì ổng phải map mấy cái mã lỗi trả về để show cho user. Việc này thì ổng nói không phải là việc của ổng, &amp;ldquo;It not my business&amp;rdquo;. WTF x2 ;))&lt;/p>
&lt;p>Như vậy mình cần làm cách nào đó để thỏa các yêu cầu sau:&lt;/p>
&lt;ol>
&lt;li>Signature của hàm phải tường minh. Nhìn cái hiểu liền&lt;/li>
&lt;li>Trả về cho thằng gọi chi tiết về lỗi nhất có thể&lt;/li>
&lt;li>Break flow khi có lỗi xảy ra&lt;/li>
&lt;/ol>
&lt;p>Sau thời gian tìm hiểu thì cái vấn đề của mình gặp thì cũng đã có rất nhiều người gặp và nó đã được giải quyết với một cách đơn giản là &lt;code>Exception&lt;/code> như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;WorkingDay less than zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">salaryPerDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;SalaryPerDay less than zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">workingDay&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Như vậy chỉ cần thêm khai báo &lt;code>throws Exception&lt;/code> và khi throw exception mình truyền thêm message thì mọi chuyện trở nên rất đơn giản.&lt;/p>
&lt;p>Demo chương trình bây giờ như sau:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">class&lt;/span> &lt;span class="nc">Salary&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">salary&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">21&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="mi">1_000_000&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;Salary: &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">salary&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bla bla ble...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="o">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">System&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getMessage&lt;/span>&lt;span class="o">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="kd">static&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">calcSalary&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">workingDay&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="kd">throws&lt;/span> &lt;span class="n">Exception&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">workingDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;WorkingDay less than zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">salaryPerDay&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s">&amp;#34;SalaryPerDay less than zero&amp;#34;&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">workingDay&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">salaryPerDay&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Các bạn có thể thay thế thay thế &lt;code>workingDay&lt;/code> hoặc &lt;code>salaryPerDay&lt;/code> nhỏ hơn 0 để xem kết quả nhé
&lt;div style="width: 100%; height: 100%;text-align: center;">
&lt;video autoplay loop muted playsinline src="https://media.giphy.com/media/7j3UoXzbjvaIo/giphy.mp4">&lt;/video>
&lt;/div>
&lt;strong>Kết luận:&lt;/strong> bằng việc sử dụng &lt;code>Exception&lt;/code> ta có thể:&lt;/p>
&lt;ul>
&lt;li>Làm cho method signature dễ hiểu&lt;/li>
&lt;li>Trả về thêm thông tin lỗi (nếu có) bằng cách sử dụng &lt;code>custom Exception&lt;/code>, mình sẽ có bài nói rõ hơn về cái này nhé.&lt;/li>
&lt;li>Code control bên ngoài dễ hiểu hơn khi tách biệt code bussiness và handle lỗi, mình cũng sẽ có bài về phần này&lt;/li>
&lt;/ul></description><category domain="https://trile.dev/categories/clean-code/">Clean Code</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/clean-code/">clean-code</category><category domain="https://trile.dev/tags/exception/">exception</category></item><item><title>Java String Concatenation Performance</title><link>https://trile.dev/post/2019-03-19-java-string-concatenation-performance/</link><guid isPermaLink="true">https://trile.dev/post/2019-03-19-java-string-concatenation-performance/</guid><pubDate>Mon, 18 Mar 2019 21:35:56 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>Hello anh em!&lt;br>
Ở bài &lt;a href="https://trile.dev/post/2019-03-05-benchmark-with-jmh-and-gradle/">trước&lt;/a> mình đã giới thiệu các bạn cách tạo một project JMH với Gradle. Bài này mình sẽ so sánh hiệu năng các cách nối chuỗi trong Java.&lt;/p>
&lt;p>Cuối bài mình có show một report như sau:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">Benchmark&lt;/th>
&lt;th style="text-align:center">Mode&lt;/th>
&lt;th style="text-align:center">Cnt&lt;/th>
&lt;th style="text-align:center">Score&lt;/th>
&lt;th style="text-align:center">&lt;/th>
&lt;th style="text-align:center">Error&lt;/th>
&lt;th style="text-align:center">Units&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBuffer&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">13566863.27&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">427443.554&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBufferx0005&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">5529261.499&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">277625.096&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBufferx1000&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">36998.492&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">2895.325&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBuilder&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">13462457.33&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">978240.749&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBuilderx0005&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">5466705.447&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">176616.966&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringBuilderx1000&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">36989.126&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">1716.705&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringConcat&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">27930719.3&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">581249.324&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringConcatx0005&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">7170529.805&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">383608.303&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringConcatx1000&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">47104.039&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">2358.121&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringJoin&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">10204201.92&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">463528.75&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringJoinx0005&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">4322622.068&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">49032.328&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringJoinx1000&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">30493.885&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">1708.261&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringPlus&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">13689364.1&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">509784.615&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringPlusx0005&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">5590364.456&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">277476.212&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">StringAppend.bmStringPlusx1000&lt;/td>
&lt;td style="text-align:center">thrpt&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td style="text-align:center">288.086&lt;/td>
&lt;td style="text-align:center">±&lt;/td>
&lt;td style="text-align:center">15.175&lt;/td>
&lt;td style="text-align:center">ops/s&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>đây là kết quả về &lt;em>so sánh hiệu năng các cách nối chuỗi trong Java&lt;/em>.&lt;/p>
&lt;p>Và giờ mình sẽ làm giải thích vì sao lại có kết quả như vậy.&lt;/p>
&lt;h3 id="StringPlus">1. String Plus (Toán tử cộng)&lt;/h3>
&lt;p>Đây là cách nối chuỗi phổ biến nhất trong Java. Ví dụ:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">String&lt;/span> &lt;span class="n">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Hello &amp;#34;&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">str&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="s">&amp;#34;world&amp;#34;&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>dòng 1 sẽ tạo ra 1 đối tượng String có giá trị &amp;ldquo;Hello&amp;rdquo;, dòng 2 sẽ tạo một String khác có giá trị &amp;ldquo;Hello world&amp;rdquo;, nhưng trước khi tạo ra 1 String mới Java sẽ kiểm tra đối tượng đó đã ở trong String Poll hay không.
Trường hợp có sẽ không tạo ra String mới mà dùng String trong pool, nếu không có sẽ tạo ra String mới và thêm vào pool (mình sẽ có bài nói chi tiết hơn).&lt;/p>
&lt;p>Như kết quả mình show thì nó cách này có hiệu năng tốt ở x1 và x5 nhưng tệ nhất với x1000. Vì khi này Java sẽ chỉ tạo 1 vài String và sẽ
không làm ảnh hưởng tới performance với số lần lặp lớn.&lt;/p>
&lt;h3 id="StringConcat">2. String Concat&lt;/h3>
&lt;p>So sánh với String Plus thì tốc độ chênh lệch rất lớn. Vậy tại sao mà có chênh lệch lớn thế? Ta cùng xem code nhé:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="n">String&lt;/span> &lt;span class="nf">concat&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">otherLen&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">length&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">otherLen&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">len&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">length&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="o">[]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Arrays&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">copyOf&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">len&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">otherLen&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">str&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getChars&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">len&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">String&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dòng code trên sẽ tạo ra 1 String mới bằng cách copy char array của 2 String trên. Như thế sẽ không có sự tham gia của String Pool và sẽ tiết kiệm được kha khá chi phí.&lt;/p>
&lt;h3 id="StringBuilder">3. String Builder&lt;/h3>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="n">AbstractStringBuilder&lt;/span> &lt;span class="nf">append&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">str&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">appendNull&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">len&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">length&lt;/span>&lt;span class="o">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ensureCapacityInternal&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">count&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">len&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">str&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">getChars&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">len&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">count&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">count&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">len&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">private&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">ensureCapacityInternal&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">minimumCapacity&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// overflow-conscious code
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="o">(&lt;/span>&lt;span class="n">minimumCapacity&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">length&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Arrays&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">copyOf&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">newCapacity&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">minimumCapacity&lt;/span>&lt;span class="o">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ở trên là 2 phương thức sẽ được gọi khi ta thực hiện phương thức &lt;code>append()&lt;/code>.
Như ta thấy tinh thần cũng giống với concat ngoại trừ việc trả về &lt;code>AbstractStringBuilder&lt;/code> thay vì tạo ra một String mới&lt;/p>
&lt;h3 id="StringBuffer">4. String Buffer&lt;/h3>
&lt;p>&lt;code>String Buffer&lt;/code> là phiên bản &lt;code>Thread safe&lt;/code> của &lt;code>String Builder&lt;/code> nên việc kết quả chậm hơn là hiển nhiên. Ta có thể xem qua code sau để hiểu cách implement thread safe:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="kd">synchronized&lt;/span> &lt;span class="n">StringBuffer&lt;/span> &lt;span class="nf">append&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">String&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">toStringCache&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">super&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">append&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="o">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Từ khóa &lt;code>synchronized&lt;/code> chỉ định trong một thời điểm chỉ có một thread có thể thực hiện được method, và nhờ có nó sẽ đảm bảo thread safe.&lt;/p>
&lt;h3 id="5-string-join">5. String Join&lt;/h3>
&lt;p>&lt;strong>Kết luận:&lt;/strong>&lt;/p>
&lt;p>Nếu còn thiếu cách nào anh em có thể comment hoặc là tạo merge request để mình update thêm nhé ; ))&lt;/p></description><category domain="https://trile.dev/categories/performance/">Performance</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/jmh/">jmh</category><category domain="https://trile.dev/tags/string/">string</category><category domain="https://trile.dev/tags/concatenation/">concatenation</category><category domain="https://trile.dev/tags/performance/">performance</category></item><item><title>Benchmark với Jmh và Gradle</title><link>https://trile.dev/post/2019-03-05-benchmark-with-jmh-and-gradle/</link><guid isPermaLink="true">https://trile.dev/post/2019-03-05-benchmark-with-jmh-and-gradle/</guid><pubDate>Tue, 05 Mar 2019 18:29:49 +0700</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>JMH là Java Microbenchmark Harness. JMH là công cụ giúp cho cho việc benchmark được chính xác và dễ đàng hơn.&lt;br>
Việc benchmark này cực kỳ có ích đối với ứng dụng cần tốc độ cao, giúp chọn ra thuật toán hay thư viện cho tốc độ tốt nhất.&lt;/p>
&lt;p>OK! Lý thuyết vậy đủ rồi, đi vào thực hành nào. Việc chúng ta cần làm là viết 1 project so sánh tốc độ của các cách nối chuỗi trong Java. Nhớ cài java và gradle trước nhé anh em&lt;/p>
&lt;p>B1: Tạo ra 1 gradle project. Các bạn mở Terminal ra và gõ lệnh sau:&lt;br>
&lt;code>gradle init&lt;/code>&lt;br>
rồi chọn những option sau:&lt;/p>
&lt;pre tabindex="0">&lt;code>Select type of project to generate:
1: basic
2: groovy-application
3: groovy-library
4: java-application
5: java-library
6: kotlin-application
7: kotlin-library
8: scala-library
Enter selection (default: basic) [1..8] 4
Select build script DSL:
1: groovy
2: kotlin
Enter selection (default: groovy) [1..2] 1
Select test framework:
1: junit
2: testng
3: spock
Enter selection (default: junit) [1..3] 1
Project name (default: jmh-gradle-example):
Source package (default: jmh.gradle.example): tri.le.jmh
&lt;/code>&lt;/pre>&lt;p>B2: Copy Copy thư mục main ra thư mục jmh&lt;br>
&lt;code>cp -r src/main src/jmh&lt;/code>&lt;br>
Mục đích của việc này là để phân biệt 3 phần: code chính, code test và code benchmark&lt;/p>
&lt;p>B3: Update file &lt;code>build.gradle&lt;/code>, thêm &lt;code>id &amp;quot;me.champeau.gradle.jmh&amp;quot; version &amp;quot;0.4.8&amp;quot;&lt;/code> vào &lt;code>plugins&lt;/code>&lt;/p>
&lt;p>B4: Setup xong rồi, giờ viết code thôi ; )). Để nhanh thì anh em copy &lt;a href="https://gitlab.com/thanhtrixx/jmh-gradle-example/blob/master/src/jmh/java/tri/le/jmh/StringAppend.java">file&lt;/a> này về và mình sẽ giải thích luôn:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Warmup&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">timeUnit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TimeUnit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">SECONDS&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>thực hiện &amp;ldquo;làm nóng&amp;rdquo; 5 lần mỗi lần 1 giây. Vậy tại sao cần warmup? Java sẽ tự động tối ưu hóa code, vì thế khi warmup sẽ giúp ta có được kết quả benchmark chính xác&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Measurement&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">iterations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="o">,&lt;/span> &lt;span class="n">timeUnit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TimeUnit&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">SECONDS&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>thực hiện benchmark trong 5 lần mỗi lần 1 giây&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@Fork&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@State&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="n">Scope&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="na">Thread&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>JMH sẽ tạo ra 1 tiến trình con cho mỗi case benchmark. Việc tạo ra tiến trình con này để đảm bảo bộ tối ưu hóa được reset lại và kết quả benchmark được chính xác hơn&lt;/p>
&lt;p>B5: và benchmark nào&lt;br>
&lt;code>./gradlew --no-daemon clean jmh&lt;/code>&lt;br>
kết quả được show ở console hoặc có thể xem lại bằng lệnh sau:&lt;br>
&lt;code>cat build/reports/jmh/results.txt&lt;/code>&lt;/p>
&lt;pre tabindex="0">&lt;code>Benchmark Mode Cnt Score Error Units
StringAppend.bmStringBuffer thrpt 5 13566863.267 ± 427443.554 ops/s
StringAppend.bmStringBufferx1000 thrpt 5 36998.492 ± 2895.325 ops/s
StringAppend.bmStringBufferx5 thrpt 5 5529261.499 ± 277625.096 ops/s
StringAppend.bmStringBuilder thrpt 5 13462457.325 ± 978240.749 ops/s
StringAppend.bmStringBuilderx1000 thrpt 5 36989.126 ± 1716.705 ops/s
StringAppend.bmStringBuilderx5 thrpt 5 5466705.447 ± 176616.966 ops/s
StringAppend.bmStringConcat thrpt 5 27930719.298 ± 581249.324 ops/s
StringAppend.bmStringConcatx1000 thrpt 5 47104.039 ± 2358.121 ops/s
StringAppend.bmStringConcatx5 thrpt 5 7170529.805 ± 383608.303 ops/s
StringAppend.bmStringJoin thrpt 5 10204201.921 ± 463528.750 ops/s
StringAppend.bmStringJoinx1000 thrpt 5 30493.885 ± 1708.261 ops/s
StringAppend.bmStringJoinx5 thrpt 5 4322622.068 ± 49032.328 ops/s
StringAppend.bmStringPlus thrpt 5 13689364.101 ± 509784.615 ops/s
StringAppend.bmStringPlusx1000 thrpt 5 288.086 ± 15.175 ops/s
StringAppend.bmStringPlusx5 thrpt 5 5590364.456 ± 277476.212 ops/s
&lt;/code>&lt;/pre>&lt;p>Anh em có thể tham khảo &lt;a href="https://gitlab.com/thanhtrixx/jmh-gradle-example">git repo&lt;/a> sau nhé. :))&lt;/p></description><category domain="https://trile.dev/categories/performance/">Performance</category><category domain="https://trile.dev/tags/java/">java</category><category domain="https://trile.dev/tags/jmh/">jmh</category><category domain="https://trile.dev/tags/gradle/">gradle</category><category domain="https://trile.dev/tags/performance/">performance</category></item><item><title>First post</title><link>https://trile.dev/post/2019-02-28-first-post/</link><guid isPermaLink="true">https://trile.dev/post/2019-02-28-first-post/</guid><pubDate>Sun, 11 Mar 2018 00:00:00 +0000</pubDate><author>contact@trile.dev (Tri Le)</author><copyright>[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en)</copyright><description>&lt;p>This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.&lt;/p>
&lt;h2 id="headings">Headings&lt;/h2>
&lt;p>The following HTML &lt;code>&amp;lt;h1&amp;gt;&lt;/code>—&lt;code>&amp;lt;h6&amp;gt;&lt;/code> elements represent six levels of section headings. &lt;code>&amp;lt;h1&amp;gt;&lt;/code> is the highest section level while &lt;code>&amp;lt;h6&amp;gt;&lt;/code> is the lowest.&lt;/p>
&lt;h1 id="h1">H1&lt;/h1>
&lt;h2 id="h2">H2&lt;/h2>
&lt;h3 id="h3">H3&lt;/h3>
&lt;h4 id="h4">H4&lt;/h4>
&lt;h5 id="h5">H5&lt;/h5>
&lt;h6 id="h6">H6&lt;/h6>
&lt;h2 id="paragraph">Paragraph&lt;/h2>
&lt;p>Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.&lt;/p>
&lt;p>Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.&lt;/p>
&lt;h2 id="blockquotes">Blockquotes&lt;/h2>
&lt;p>The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a &lt;code>footer&lt;/code> or &lt;code>cite&lt;/code> element, and optionally with in-line changes such as annotations and abbreviations.&lt;/p>
&lt;h4 id="blockquote-without-attribution">Blockquote without attribution&lt;/h4>
&lt;blockquote>
&lt;p>Tiam, ad mint andaepu dandae nostion secatur sequo quae.
&lt;strong>Note&lt;/strong> that you can use &lt;em>Markdown syntax&lt;/em> within a blockquote.&lt;/p>
&lt;/blockquote>
&lt;h4 id="blockquote-with-attribution">Blockquote with attribution&lt;/h4>
&lt;blockquote>
&lt;p>Don&amp;rsquo;t communicate by sharing memory, share memory by communicating.&lt;br>
— &lt;cite>Rob Pike&lt;sup id="fnref:1">&lt;a href="https://trile.dev/post/2019-02-28-first-post/#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>&lt;/cite>&lt;/p>
&lt;/blockquote>
&lt;h2 id="tables">Tables&lt;/h2>
&lt;p>Tables aren&amp;rsquo;t part of the core Markdown spec, but Hugo supports supports them out-of-the-box.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Name&lt;/th>
&lt;th>Age&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Bob&lt;/td>
&lt;td>27&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Alice&lt;/td>
&lt;td>23&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h4 id="inline-markdown-within-tables">Inline Markdown within tables&lt;/h4>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Italics&lt;/th>
&lt;th>Bold&lt;/th>
&lt;th>Code&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;em>italics&lt;/em>&lt;/td>
&lt;td>&lt;strong>bold&lt;/strong>&lt;/td>
&lt;td>&lt;code>code&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="code-blocks">Code Blocks&lt;/h2>
&lt;h4 id="code-block-with-backticks">Code block with backticks&lt;/h4>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&amp;lt;!doctype html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span> &lt;span class="na">lang&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;en&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">charset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Example HTML5 Document&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Test&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="code-block-indented-with-four-spaces">Code block indented with four spaces&lt;/h4>
&lt;pre>&lt;code>&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;Example HTML5 Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;p&amp;gt;Test&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code>&lt;/pre>
&lt;h4 id="code-block-with-hugos-internal-highlight-shortcode">Code block with Hugo&amp;rsquo;s internal highlight shortcode&lt;/h4>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&amp;lt;!doctype html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span> &lt;span class="na">lang&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;en&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">charset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Example HTML5 Document&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Test&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>
&lt;h2 id="list-types">List Types&lt;/h2>
&lt;h4 id="ordered-list">Ordered List&lt;/h4>
&lt;ol>
&lt;li>First item&lt;/li>
&lt;li>Second item&lt;/li>
&lt;li>Third item&lt;/li>
&lt;/ol>
&lt;h4 id="unordered-list">Unordered List&lt;/h4>
&lt;ul>
&lt;li>List item&lt;/li>
&lt;li>Another item&lt;/li>
&lt;li>And another item&lt;/li>
&lt;/ul>
&lt;h4 id="nested-list">Nested list&lt;/h4>
&lt;ul>
&lt;li>Fruit
&lt;ul>
&lt;li>Apple&lt;/li>
&lt;li>Orange&lt;/li>
&lt;li>Banana&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Dairy
&lt;ul>
&lt;li>Milk&lt;/li>
&lt;li>Cheese&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="other-elements--abbr-sub-sup-kbd-mark">Other Elements — abbr, sub, sup, kbd, mark&lt;/h2>
&lt;p>&lt;abbr title="Graphics Interchange Format">GIF&lt;/abbr> is a bitmap image format.&lt;/p>
&lt;p>H&lt;sub>2&lt;/sub>O&lt;/p>
&lt;p>X&lt;sup>n&lt;/sup> + Y&lt;sup>n&lt;/sup> = Z&lt;sup>n&lt;/sup>&lt;/p>
&lt;p>Press &lt;kbd>&lt;kbd>CTRL&lt;/kbd>+&lt;kbd>ALT&lt;/kbd>+&lt;kbd>Delete&lt;/kbd>&lt;/kbd> to end the session.&lt;/p>
&lt;p>Most &lt;mark>salamanders&lt;/mark> are nocturnal, and hunt for insects, worms, and other small creatures.&lt;/p>
&lt;h2 id="emoji">Emoji&lt;/h2>
&lt;p>&lt;a href="https://gist.github.com/rxaviers/7360908#file-gistfile1-md">https://gist.github.com/rxaviers/7360908#file-gistfile1-md&lt;/a>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>The above quote is excerpted from Rob Pike&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=PAAkCSZUG1c">talk&lt;/a> during Gopherfest, November 18, 2015.&amp;#160;&lt;a href="https://trile.dev/post/2019-02-28-first-post/#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description><category domain="https://trile.dev/series/markdown/">Markdown</category></item></channel></rss>