├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
└── javatips
├── debug
├── Example1.java
├── Example2.java
├── Example3.java
├── Example4.java
├── Example5.java
└── Example6.java
├── designpattern
└── cor
│ ├── ChainClient.java
│ ├── ClipHandler.java
│ ├── ExportHandler.java
│ ├── NoiseReductionHandler.java
│ ├── SubtitleHandler.java
│ ├── Video.java
│ └── package-info.java
├── exception
├── Example1.java
├── Example2.java
├── Example3.java
├── Example4.java
├── Example5.java
├── Example6.java
├── Example7.java
├── Example8.java
└── Example9.java
├── jvmtools
├── HelloWorld.java
├── jcmd
│ └── README.md
└── jstack
│ ├── DeadLockExample.java
│ ├── HighCPUExample.java
│ ├── README.md
│ ├── WaitExample.java
│ └── WaitIOExample.java
├── lambda
└── exception
│ ├── Example.java
│ ├── LambdaExceptionUtil.java
│ └── Unchecked.java
└── package-info.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 |
24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
25 | hs_err_pid*
26 | ### JetBrains template
27 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
28 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
29 |
30 | # User-specific stuff
31 | .idea/**/workspace.xml
32 | .idea/**/tasks.xml
33 | .idea/**/dictionaries
34 | .idea/**/shelf
35 |
36 | # Sensitive or high-churn files
37 | .idea/**/dataSources/
38 | .idea/**/dataSources.ids
39 | .idea/**/dataSources.local.xml
40 | .idea/**/sqlDataSources.xml
41 | .idea/**/dynamic.xml
42 | .idea/**/uiDesigner.xml
43 | .idea/**/dbnavigator.xml
44 |
45 | # Gradle
46 | .idea/**/gradle.xml
47 | .idea/**/libraries
48 |
49 | # CMake
50 | cmake-build-debug/
51 | cmake-build-release/
52 |
53 | # Mongo Explorer plugin
54 | .idea/**/mongoSettings.xml
55 |
56 | # File-based project format
57 | *.iws
58 |
59 | # IntelliJ
60 | out/
61 |
62 | # mpeltonen/sbt-idea plugin
63 | .idea_modules/
64 |
65 | # JIRA plugin
66 | atlassian-ide-plugin.xml
67 |
68 | # Cursive Clojure plugin
69 | .idea/replstate.xml
70 |
71 | # Crashlytics plugin (for Android Studio and IntelliJ)
72 | com_crashlytics_export_strings.xml
73 | crashlytics.properties
74 | crashlytics-build.properties
75 | fabric.properties
76 |
77 | # Editor-based Rest Client
78 | .idea/httpRequests
79 | ### Maven template
80 | target/
81 | pom.xml.tag
82 | pom.xml.releaseBackup
83 | pom.xml.versionsBackup
84 | pom.xml.next
85 | release.properties
86 | dependency-reduced-pom.xml
87 | buildNumber.properties
88 | .mvn/timing.properties
89 |
90 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
91 | !/.mvn/wrapper/maven-wrapper.jar
92 |
93 | .idea/
94 | *.iml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, 王爵nice biezhi.me@gmail.com
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Java 编程技巧
2 |
3 | 这个仓库存储了 Java 语言中的经典问题处理方式,以及编写优雅、高性能代码的最佳实践。
4 | 所有的代码都有视频讲解。
5 |
6 | ## 阅读须知
7 |
8 | - 代码使用 `maven` 构建
9 | - 基于 Java8
10 |
11 | ## 视频位置
12 |
13 | - [Youtube](https://www.youtube.com/playlist?list=PLK2w-tGRdrj7SUZ1m2tMJ3FKb5SCn7r7I)
14 | - [Bilibili](https://www.bilibili.com/video/av27652260/)
15 |
16 | ## 目录
17 |
18 | - lambda 中如何处理异常?[视频](https://youtu.be/W3OfqnTVkbc) / [代码](src/main/java/javatips/lambda/exception)
19 | - 从开源框架聊聊责任链模式的应用 [视频](https://youtu.be/O7u6tNLXL_k) / [代码](https://github.com/biezhi/java-tips/blob/master/src/main/java/javatips/javatips/designpattern/cor)
20 | - 不做 BUG 仔,必须 GET 的 IDEA 调试技巧 [视频](https://youtu.be/b8swwmdNUek) / [代码](src/main/java/javatips/debug)
21 | - 异常处理最佳实践 [视频](https://youtu.be/J_Ubcw4_6rQ) / [代码](src/main/java/javatips/exception)
22 |
23 | ## 其他
24 |
25 | 欢迎在 issue 中提建议,youtube 视频的留言都会回复。
26 |
27 | ## License
28 |
29 | [BSD3](LICENSE)
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | io.github.biezhi
8 | java-tips
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.slf4j
14 | slf4j-api
15 | 1.7.25
16 | compile
17 |
18 |
19 | ch.qos.logback
20 | logback-classic
21 | 1.2.3
22 |
23 |
24 |
25 |
26 |
27 |
28 | org.apache.maven.plugins
29 | maven-compiler-plugin
30 |
31 | 1.8
32 | 1.8
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example1.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | /**
4 | * 基本使用
5 | *
6 | * @author biezhi
7 | * @date 2018/8/17
8 | */
9 | public class Example1 {
10 |
11 | static class CustomException extends RuntimeException {
12 | public CustomException(String message) {
13 | super(message);
14 | }
15 | }
16 |
17 | private static void helloIntelliJ() {
18 | System.out.println("我来自北方,请不要为难我");
19 | System.out.println("因为我只是一只小猫咪");
20 | Runtime runtime = Runtime.getRuntime();
21 | // throw new CustomException("I,m worry.");
22 | }
23 |
24 | public static void main(String[] args) {
25 | helloIntelliJ();
26 | System.out.println("No 啪不了木.");
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example2.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | /**
4 | * 条件断点
5 | *
6 | * @author biezhi
7 | * @date 2018/8/14
8 | */
9 | public class Example2 {
10 |
11 | private static void execute(int num) {
12 | System.out.println("execute: " + num);
13 | // TODO
14 | }
15 |
16 | public static void main(String[] args) {
17 | for (int i = 0; i < 1000; i++) {
18 | execute(i);
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example3.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | /**
4 | * 回到上一步
5 | *
6 | * @author biezhi
7 | * @date 2018/8/14
8 | */
9 | public class Example3 {
10 |
11 | private static int excludeO(String str) {
12 | str = str.toLowerCase();
13 | int count = str.replaceAll("[^o]+", "").length();
14 | System.out.println("asdasdad");
15 | return count;
16 | }
17 |
18 | static class User {
19 | String username;
20 | String password;
21 |
22 | public User(String username, String password) {
23 | this.username = username;
24 | this.password = password;
25 | }
26 | }
27 |
28 | public static void main(String[] args) {
29 | User user = new User("biezhi", "123456");
30 | if(user.username.isEmpty()){
31 | System.out.println("username is empty.");
32 | }
33 | String name = "Hello W0rld";
34 | int count = excludeO(name);
35 | System.out.println(count);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example4.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | import java.util.concurrent.ExecutorService;
4 | import java.util.concurrent.Executors;
5 |
6 | /**
7 | * 多线程调试
8 | *
9 | * @author biezhi
10 | * @date 2018/8/14
11 | */
12 | public class Example4 {
13 |
14 | public static void main(String[] args) {
15 | ExecutorService executorService = Executors.newFixedThreadPool(5);
16 |
17 | Runnable r1 = () -> {
18 | System.out.println("当前线程: " + Thread.currentThread().getName());
19 | System.out.println("少小离家老大回,菊花变成向日葵。");
20 | };
21 |
22 | Runnable r2 = () -> {
23 | System.out.println("当前线程: " + Thread.currentThread().getName());
24 | System.out.println("有钱人终成眷属,有情人终生痛苦。");
25 | };
26 |
27 | Runnable r3 = () -> {
28 | System.out.println("当前线程: " + Thread.currentThread().getName());
29 | System.out.println("问世间情为何物,不过一物降一物。");
30 | };
31 |
32 | executorService.execute(r1);
33 | executorService.execute(r2);
34 | executorService.execute(r3);
35 |
36 | System.out.println("山外青山楼外楼,没房结婚真发愁。");
37 |
38 | executorService.shutdown();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example5.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | /**
4 | * 中断调试
5 | *
6 | * @author biezhi
7 | * @date 2018/8/14
8 | */
9 | public class Example5 {
10 |
11 | public static void main(String[] args) {
12 | System.out.println("小明开心的上了一辆童车");
13 | System.out.println("路过南京路...");
14 | System.out.println("路过秋名山...");
15 | System.out.println("前方有危险,司机请注意");
16 | System.out.println("你有权保持沉默,但是你所说的一切将作为呈堂证供。");
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/javatips/debug/Example6.java:
--------------------------------------------------------------------------------
1 | package javatips.debug;
2 |
3 | /**
4 | * 远程调试
5 | *
6 | * java -server -Xms512m -Xmx512m -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9081 -Djava.ext.dirs=. ${main_class}
7 | *
8 | * @author biezhi
9 | * @date 2018/8/18
10 | */
11 | public class Example6 {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/ChainClient.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | *
5 | * @author biezhi
6 | * @date 2018/8/2
7 | */
8 | public class ChainClient {
9 |
10 | public static void main(String[] args) {
11 | NoiseReductionHandler noiseReductionHandler = new NoiseReductionHandler();
12 | SubtitleHandler subtitleHandler = new SubtitleHandler();
13 | ExportHandler exportHandler = new ExportHandler();
14 |
15 | noiseReductionHandler.setNext(subtitleHandler);
16 | subtitleHandler.setNext(exportHandler);
17 |
18 | Video video = new Video("ok", null, false);
19 | noiseReductionHandler.handle(video);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/ClipHandler.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | * 责任链模式中抽象处理角色
5 | *
6 | * @author biezhi
7 | * @date 2018/8/2
8 | */
9 | public abstract class ClipHandler {
10 |
11 | private ClipHandler next;
12 |
13 | public abstract void handle(Video video);
14 |
15 | public void invokeNext(Video video){
16 | if(next != null){
17 | next.handle(video);
18 | }
19 | }
20 |
21 | public ClipHandler getNext() {
22 | return next;
23 | }
24 |
25 | public void setNext(ClipHandler next) {
26 | this.next = next;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/ExportHandler.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | * 视频导出处理器你
5 | *
6 | * @author biezhi
7 | * @date 2018/8/2
8 | */
9 | public class ExportHandler extends ClipHandler {
10 | @Override
11 | public void handle(Video video) {
12 | if(!video.isExport()){
13 | System.out.println("导出视频...");
14 | }
15 | this.invokeNext(video);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/NoiseReductionHandler.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | * 降噪处理器
5 | *
6 | * @author biezhi
7 | * @date 2018/8/2
8 | */
9 | public class NoiseReductionHandler extends ClipHandler {
10 | @Override
11 | public void handle(Video video) {
12 | if(video.getVoice() != null){
13 | System.out.println("降噪处理...");
14 | }
15 | this.invokeNext(video);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/SubtitleHandler.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | * 字幕处理器
5 | *
6 | * @author biezhi
7 | * @date 2018/8/2
8 | */
9 | public class SubtitleHandler extends ClipHandler {
10 | @Override
11 | public void handle(Video video) {
12 | if(video.getSubtitle() == null){
13 | System.out.println("添加字幕...");
14 | }
15 | this.invokeNext(video);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/Video.java:
--------------------------------------------------------------------------------
1 | package javatips.designpattern.cor;
2 |
3 | /**
4 | * 视频实体
5 | *
6 | * @author biezhi
7 | * @date 2018/8/2
8 | */
9 | public class Video {
10 |
11 | private String voice;
12 | private String subtitle;
13 | private boolean isExport;
14 |
15 | public Video(String voice, String subtitle, boolean isExport) {
16 | this.voice = voice;
17 | this.subtitle = subtitle;
18 | this.isExport = isExport;
19 | }
20 |
21 | public String getVoice() {
22 | return voice;
23 | }
24 |
25 | public void setVoice(String voice) {
26 | this.voice = voice;
27 | }
28 |
29 | public String getSubtitle() {
30 | return subtitle;
31 | }
32 |
33 | public void setSubtitle(String subtitle) {
34 | this.subtitle = subtitle;
35 | }
36 |
37 | public boolean isExport() {
38 | return isExport;
39 | }
40 |
41 | public void setExport(boolean export) {
42 | isExport = export;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/javatips/designpattern/cor/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Chain of Responsibility / 责任链
3 | *
4 | * @author biezhi
5 | * @date 2018/8/2
6 | */
7 | package javatips.designpattern.cor;
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example1.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 |
11 | /**
12 | * 在 Finally 中清理资源,或者使用 Try-With-Resource 语句
13 | *
14 | * @author biezhi
15 | * @date 2018/9/18
16 | */
17 | public class Example1 {
18 |
19 | private static final Logger log = LoggerFactory.getLogger(Example1.class);
20 |
21 | public void doNotCloseResourceInTry() {
22 | FileInputStream inputStream = null;
23 | try {
24 | File file = new File("./王爵的私有宝贝.txt");
25 | inputStream = new FileInputStream(file);
26 | // 使用 inputStream 读取文件内容
27 |
28 | // 兄弟,不要这么做
29 | inputStream.close();
30 | } catch (FileNotFoundException e) {
31 | log.error("", e);
32 | } catch (IOException e) {
33 | log.error("", e);
34 | }
35 | }
36 |
37 | public void closeResourceInFinally() {
38 | FileInputStream inputStream = null;
39 | try {
40 | File file = new File("./王爵的私有宝贝.txt");
41 | inputStream = new FileInputStream(file);
42 | // 使用 inputStream 读取文件内容
43 |
44 | } catch (FileNotFoundException e) {
45 | log.error("", e);
46 | } catch (IOException e) {
47 | log.error("", e);
48 | } finally {
49 | if(null != inputStream){
50 | try {
51 | inputStream.close();
52 | } catch (IOException e) {
53 | log.error("关闭流失败", e);
54 | }
55 | }
56 | }
57 | }
58 |
59 | public void autoCloseResource() {
60 | File file = new File("./王爵的私有宝贝.txt");
61 | try (FileInputStream inputStream = new FileInputStream(file)){
62 | // 使用 inputStream 读取文件内容
63 |
64 | } catch (FileNotFoundException e) {
65 | log.error("", e);
66 | } catch (IOException e) {
67 | log.error("", e);
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example2.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | /**
4 | * 指定具体异常
5 | *
6 | * @author biezhi
7 | * @date 2018/9/18
8 | */
9 | public class Example2 {
10 |
11 | public void doNotDoThis() throws Exception {
12 | Integer year = Integer.parseInt("biezhi???");
13 | System.out.println("哦 " + year);
14 | }
15 |
16 | public void doThis() throws NumberFormatException {
17 | Integer year = Integer.parseInt("biezhi???");
18 | System.out.println("哦 " + year);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example3.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | /**
4 | * 给异常加点说明
5 | *
6 | * @author biezhi
7 | * @date 2018/9/18
8 | */
9 | public class Example3 {
10 |
11 | class NotFoundGirlFriendException extends Exception {
12 |
13 | public NotFoundGirlFriendException(String message) {
14 | super(message);
15 | }
16 | }
17 |
18 | /**
19 | * 当心抛出 NotFoundGirlFriendException...
20 | *
21 | * @param input
22 | * @throws NotFoundGirlFriendException 如果你不订阅 ... 那么😁😁😁
23 | */
24 | public void doSomething(String input) throws NotFoundGirlFriendException {
25 |
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example4.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * 使用描述性消息抛出异常
8 | *
9 | * @author biezhi
10 | * @date 2018/9/18
11 | */
12 | public class Example4 {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(Example4.class);
15 |
16 | public void foo() {
17 | try {
18 | new Long("biezhi大法好");
19 | } catch (NumberFormatException e) {
20 | log.error("用户ID格式化失败", e);
21 | }
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example5.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * 优先捕获具体异常
8 | *
9 | * @author biezhi
10 | * @date 2018/9/18
11 | */
12 | public class Example5 {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(Example5.class);
15 |
16 | public void catchMostSpecificExceptionFirst() {
17 | try {
18 | doSomething("不要跟我讲这些,因为我只是一只小猫咪!");
19 | } catch (NumberFormatException e) {
20 | log.error("字符串转数字失败", e);
21 | } catch (IllegalArgumentException e) {
22 | log.error("非法参数", e);
23 | }
24 | }
25 |
26 | private void doSomething(String message) {
27 | Integer emmm = Integer.parseInt(message);
28 | }
29 |
30 | public static void main(String[] args) {
31 | new Example5().catchMostSpecificExceptionFirst();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example6.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | /**
4 | * 不要捕获 Throwable
5 | *
6 | * @author biezhi
7 | * @date 2018/9/18
8 | */
9 | public class Example6 {
10 |
11 | public void doNotCatchThrowable() {
12 | try {
13 | // 做点什么吧
14 | } catch (Throwable t) {
15 | // 停下来,不要 🙅 这么干
16 | }
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example7.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * 不要忽略异常
8 | *
9 | * @author biezhi
10 | * @date 2018/9/18
11 | */
12 | public class Example7 {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(Example7.class);
15 |
16 | public void doNotIgnoreExceptions() {
17 | try {
18 | // 做点什么吧,先生
19 | } catch (NumberFormatException e) {
20 | // 嘤该不会走到这里(不,一定不会的)
21 | log.error("不可能走到的", e);
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example8.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | /**
7 | * 不要同时记录并抛出异常
8 | *
9 | * @author biezhi
10 | * @date 2018/9/18
11 | */
12 | public class Example8 {
13 |
14 | private static final Logger log = LoggerFactory.getLogger(Example8.class);
15 |
16 | public void foo() {
17 | try {
18 | new Long("xyz");
19 | } catch (NumberFormatException e) {
20 | // log.error("", e);
21 | throw e;
22 | }
23 | }
24 |
25 | public static void main(String[] args) {
26 | new Example8().foo();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/javatips/exception/Example9.java:
--------------------------------------------------------------------------------
1 | package javatips.exception;
2 |
3 | /**
4 | * 包装异常不要丢弃原始异常
5 | *
6 | * @author biezhi
7 | * @date 2018/9/18
8 | */
9 | public class Example9 {
10 |
11 | class MyBusinessException extends Exception {
12 | public MyBusinessException(String message) {
13 | super(message);
14 | }
15 | public MyBusinessException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | }
20 |
21 | public void wrapException(String id) throws MyBusinessException {
22 | try {
23 | long userId = Long.parseLong(id);
24 | System.out.println("userId: " + userId);
25 | } catch (NumberFormatException e) {
26 | throw new MyBusinessException("描述错误的消息", e);
27 | }
28 | }
29 |
30 | public static void main(String[] args) throws MyBusinessException {
31 | new Example9().wrapException("emmm");
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/HelloWorld.java:
--------------------------------------------------------------------------------
1 | package javatips.jvmtools;
2 |
3 | import java.util.Arrays;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | /**
7 | * @author biezhi
8 | * @date 2018/10/12
9 | */
10 | public class HelloWorld {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | System.out.println("args: " + Arrays.toString(args));
14 | while (true) {
15 | System.out.println("2333");
16 | TimeUnit.SECONDS.sleep(1);
17 | }
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jcmd/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 参数含义
3 |
4 | - `Thread.print`: 查看线程堆栈信息
5 | - `GC.class_histogram`: 查看系统中类统计信息
6 | - `GC.heap_dump`: 导出 JVM 的 Heap Dump
7 | - `GC.run_finalization`: 对 JVM 执行 `java.lang.System.runFinalization()`
8 | - `GC.run`: 对 JVM 执行 `java.lang.System.gc()`
9 | - `VM.uptime`: 查看 JVM 的启动时长
10 | - `VM.flags`: 查看 JVM 的启动参数
11 | - `VM.system_properties`: 查看 JVM 的属性信息
12 | - `VM.command_line`: 查看 JVM 的启动命令行
13 | - `VM.version`: 查看目标 JVM 进程的版本信息
14 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jstack/DeadLockExample.java:
--------------------------------------------------------------------------------
1 | package javatips.jvmtools.jstack;
2 |
3 | /**
4 | * 死锁
5 | */
6 | public class DeadLockExample {
7 |
8 | private static Object Lock1 = new Object();
9 | private static Object Lock2 = new Object();
10 |
11 | private static class ThreadDemo1 extends Thread {
12 | public void run() {
13 | synchronized (Lock1) {
14 | System.out.println("Thread 1: 持有 Lock1...");
15 |
16 | try {
17 | Thread.sleep(10);
18 | } catch (InterruptedException e) {
19 |
20 | }
21 |
22 | System.out.println("Thread 1: 等待 Lock2...");
23 |
24 | synchronized (Lock2) {
25 | System.out.println("Thread 1: 持有 Lock1 & 2...");
26 | }
27 | }
28 | }
29 | }
30 |
31 | private static class ThreadDemo2 extends Thread {
32 | public void run() {
33 | synchronized (Lock2) {
34 | System.out.println("Thread 2: 持有 Lock2...");
35 |
36 | try {
37 | Thread.sleep(10);
38 | } catch (InterruptedException e) {
39 |
40 | }
41 |
42 | System.out.println("Thread 2: 等待 Lock1...");
43 |
44 | synchronized (Lock1) {
45 | System.out.println("Thread 2: 持有 Lock1 & 2...");
46 | }
47 | }
48 | }
49 | }
50 |
51 | public static void main(String[] args) {
52 | new ThreadDemo1().start();
53 | new ThreadDemo2().start();
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jstack/HighCPUExample.java:
--------------------------------------------------------------------------------
1 | package javatips.jvmtools.jstack;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | /**
6 | * CPU 过高
7 | */
8 | public class HighCPUExample {
9 |
10 | private static int count;
11 |
12 | private static void calc() {
13 | count++;
14 | }
15 |
16 | public static void main(String[] args) throws InterruptedException {
17 | // 开启子线程
18 | Thread thread1 = new Thread(() -> {
19 | while (true) {
20 | calc();
21 | }
22 | });
23 | thread1.setName("occupy-cpu");
24 | thread1.start();
25 |
26 | System.out.println("tid:" + thread1.getId());
27 |
28 | Thread thread2 = new Thread(() -> {
29 | while (true) {
30 | try {
31 | TimeUnit.SECONDS.sleep(3);
32 | System.out.println("dididi 稳定运行");
33 | } catch (Exception e) {
34 | }
35 | }
36 | });
37 |
38 | thread2.setName("dididi");
39 | thread2.start();
40 |
41 | while (true) {
42 | TimeUnit.SECONDS.sleep(1);
43 | System.out.println("主线程在运行...");
44 | }
45 |
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jstack/README.md:
--------------------------------------------------------------------------------
1 | # 找到线程 ID
2 |
3 | ```bash
4 | top -Hp
5 |
6 | ```
7 |
8 | # 线程状态
9 |
10 | - 新建(NEW):表示线程被创建出来还没真正启动的状态,可以认为它是个 Java 内部状态。
11 | - 就绪(RUNNABLE):表示该线程已经在 JVM 中执行,当然由于执行需要计算资源,它可能是正在运行,也可能还在等待系统分配给它 CPU 片段,在就绪队列里面排队。
12 | - 在其他一些分析中,会额外区分一种状态 RUNNING,但是从 Java API 的角度,并不能表示出来。
13 | - 阻塞(BLOCKED):这个状态和我们前面两讲介绍的同步非常相关,阻塞表示线程在等待 Monitor lock。比如,线程试图通过 synchronized 去获取某个锁,但是其他线程已经独占了,那么当前线程就会处于阻塞状态。
14 | - 等待(WAITING):表示正在等待其他线程采取某些操作。一个常见的场景是类似生产者消费者模式,发现任务条件尚未满足,就让当前消费者线程等待(wait),另外的生产者线程去准备任务数据,然后通过类似 notify 等动作,通知消费线程可以继续工作了。Thread.join() 也会令线程进入等待状态。
15 | - 计时等待(TIMED_WAIT):其进入条件和等待状态类似,但是调用的是存在超时条件的方法,比如 wait 或 join 等方法的指定超时版本。
16 | - 终止(TERMINATED):不管是意外退出还是正常执行结束,线程已经完成使命,终止运行,也有人把这个状态叫作死亡。
17 |
18 | # Thread StackTrace State
19 |
20 | - `Deadlock`:死锁 (重点关注)
21 | - `Runnable`:执行中。该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正
22 | 在运行。
23 | - `Waiting on condition`:等待资源 (重点关注)
24 | - `Waiting on monitor entry`:等待获取监视器线程处于等待获取监视器的状态 (重点关注)
25 | - `in Object.wait()` 或 `TIMED_WAITING`:对象等待中。线程获取到监视器后发现条件不满足调用 `wait()`方法,放弃监视器。
26 | - `Suspended`:暂停
27 | - `Blocked`:阻塞 (重点关注)
28 | - `Parked`:停止
29 |
30 | # JVM 内部后台线程
31 |
32 | | 线程名称 | | 详细说明 |
33 | |:--------------------------------- |:---:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34 | | `Attach Listener` | | `Attach Listener` 线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。
通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。 如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。 |
35 | | `Signal Dispatcher` | | 前面我们提到第一个 Attach Listener 线程的职责是接收外部 jvm 命令,当命令接收成功后,会交给 signal dispather 线程去进行分发到各个不同的模块处理命令,并且返回处理结果。
signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。 |
36 | | `CompilerThread0` | | 用来调用JITing,实时编译装卸class 。
通常,jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加,例如:`CompilerThread1` |
37 | | `Concurrent Mark-Sweep GC Thread` | | 并发标记清除垃圾回收器(就是通常所说的CMS GC)线程, 该线程主要针对于老年代垃圾回收。
ps:启用该垃圾回收器,需要在jvm启动参数中加上:`-XX:+UseConcMarkSweepGC` |
38 | | `DestroyJavaVM` | | 执行 `main()` 的线程在main执行完后调用JNI中的 jni_DestroyJavaVM() 方法唤起DestroyJavaVM 线程。JVM 在 Jboss 服务器启动之后,就会唤起DestroyJavaVM 线程,处于等待状态,等待其它线程(java线程和native线程)退出时通知它卸载 JVM。线程退出时,都会判断自己当前是否是整个JVM中最后一个非 deamon 线程,如果是,则通知 DestroyJavaVM 线程卸载 JVM。 |
39 | | `Finalizer` | | 这个线程也是在main线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的finalize()方法。
关于Finalizer线程的几点:
1) 只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行;
2) 该线程也是daemon线程,因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法,JVM也会退出;
3) JVM在垃圾收集时会将失去引用的对象包装成Finalizer对象(Reference的实现),并放入ReferenceQueue,由Finalizer线程来处理;最后将该Finalizer对象的引用置为null,由垃圾收集器来回收;
4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做,很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难; |
40 | | `Gang worker#0` | | JVM 用于做新生代垃圾回收(monir gc)的一个线程。`#` 号后面是线程编号,例如:`Gang worker#1` |
41 | | `GC Daemon` | | GC Daemon 线程是JVM为RMI提供远程分布式 GC 使用的,GC Daemon线程里面会主动调用 `System.gc()` 方法,对服务器进行 Full GC。 其初衷是当 RMI 服务器返回一个对象到其客户机(远程方法的调用方)时,其跟踪远程对象在客户机中的使用。
当再没有更多的对客户机上远程对象的引用时,或者如果引用的“租借”过期并且没有更新,服务器将垃圾回收远程对象。不过,我们现在 jvm 启动参数都加上了 `-XX:+DisableExplicitGC` 配置,所以,这个线程只有打酱油的份了。 |
42 | | `Reference Handler` | | JVM 在创建 main 线程后就创建 `Reference Handler` 线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题 。 |
43 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jstack/WaitExample.java:
--------------------------------------------------------------------------------
1 | package javatips.jvmtools.jstack;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | /**
6 | * 挂起线程
7 | *
8 | * @author biezhi
9 | * @date 2018-11-05
10 | */
11 | public class WaitExample {
12 |
13 |
14 | public static void main(String[] args) throws InterruptedException {
15 | Object lock = new Object();
16 |
17 | Thread thread = new Thread(() -> {
18 | synchronized (lock) {
19 | try {
20 | lock.wait();
21 | System.out.println("hello");
22 | while (true) {
23 | TimeUnit.SECONDS.sleep(1);
24 | }
25 | } catch (InterruptedException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 | });
30 | thread.setName("jvm-wait-example");
31 | thread.start();
32 |
33 | int count = 0;
34 | while (true) {
35 | if (count == 5) {
36 | synchronized (lock) {
37 | lock.notify();
38 | }
39 | }
40 | TimeUnit.SECONDS.sleep(1);
41 | count++;
42 | }
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/javatips/jvmtools/jstack/WaitIOExample.java:
--------------------------------------------------------------------------------
1 | package javatips.jvmtools.jstack;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | /**
7 | * 等待 IO
8 | *
9 | * @author biezhi
10 | * @date 2018-11-05
11 | */
12 | public class WaitIOExample {
13 |
14 | public static void main(String[] args) throws IOException {
15 | InputStream is = System.in;
16 | int i = is.read();
17 | System.out.println("exit。");
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/javatips/lambda/exception/Example.java:
--------------------------------------------------------------------------------
1 | package javatips.lambda.exception;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 |
7 | import static javatips.lambda.exception.LambdaExceptionUtil.*;
8 |
9 | /**
10 | * @author biezhi
11 | * @date 2018/7/24
12 | */
13 | public class Example {
14 |
15 | public static List findClasses(List names) {
16 | return names.stream()
17 | .map(className -> uncheck(Class::forName, className))
18 | .collect(Collectors.toList());
19 | }
20 |
21 | public static void main(String[] args) {
22 | try {
23 | List classes = findClasses(Arrays.asList("Hello"));
24 | } catch (Exception e) {
25 | e.printStackTrace();
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/javatips/lambda/exception/LambdaExceptionUtil.java:
--------------------------------------------------------------------------------
1 | package javatips.lambda.exception;
2 |
3 | import java.util.function.BiConsumer;
4 | import java.util.function.Consumer;
5 | import java.util.function.Function;
6 | import java.util.function.Supplier;
7 |
8 | public final class LambdaExceptionUtil {
9 |
10 | @FunctionalInterface
11 | public interface Consumer_WithExceptions {
12 | void accept(T t) throws E;
13 | }
14 |
15 | @FunctionalInterface
16 | public interface BiConsumer_WithExceptions {
17 | void accept(T t, U u) throws E;
18 | }
19 |
20 | @FunctionalInterface
21 | public interface Function_WithExceptions {
22 | R apply(T t) throws E;
23 | }
24 |
25 | @FunctionalInterface
26 | public interface Supplier_WithExceptions {
27 | T get() throws E;
28 | }
29 |
30 | @FunctionalInterface
31 | public interface Runnable_WithExceptions {
32 | void run() throws E;
33 | }
34 |
35 | /**
36 | * .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println));
37 | */
38 | public static Consumer rethrowConsumer(Consumer_WithExceptions consumer) throws E {
39 | return t -> {
40 | try {
41 | consumer.accept(t);
42 | } catch (Exception exception) {
43 | throwAsUnchecked(exception);
44 | }
45 | };
46 | }
47 |
48 | public static BiConsumer rethrowBiConsumer(BiConsumer_WithExceptions biConsumer) throws E {
49 | return (t, u) -> {
50 | try {
51 | biConsumer.accept(t, u);
52 | } catch (Exception exception) {
53 | throwAsUnchecked(exception);
54 | }
55 | };
56 | }
57 |
58 | /**
59 | * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
60 | */
61 | public static Function rethrowFunction(Function_WithExceptions function) throws E {
62 | return t -> {
63 | try {
64 | return function.apply(t);
65 | } catch (Exception exception) {
66 | throwAsUnchecked(exception);
67 | return null;
68 | }
69 | };
70 | }
71 |
72 | /**
73 | * rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
74 | */
75 | public static Supplier rethrowSupplier(Supplier_WithExceptions function) throws E {
76 | return () -> {
77 | try {
78 | return function.get();
79 | } catch (Exception exception) {
80 | throwAsUnchecked(exception);
81 | return null;
82 | }
83 | };
84 | }
85 |
86 | /**
87 | * uncheck(() -> Class.forName("xxx"));
88 | */
89 | public static void uncheck(Runnable_WithExceptions t) {
90 | try {
91 | t.run();
92 | } catch (Exception exception) {
93 | throwAsUnchecked(exception);
94 | }
95 | }
96 |
97 | /**
98 | * uncheck(() -> Class.forName("xxx"));
99 | */
100 | public static R uncheck(Supplier_WithExceptions supplier) {
101 | try {
102 | return supplier.get();
103 | } catch (Exception exception) {
104 | throwAsUnchecked(exception);
105 | return null;
106 | }
107 | }
108 |
109 | /**
110 | * uncheck(Class::forName, "xxx");
111 | */
112 | public static R uncheck(Function_WithExceptions function, T t) {
113 | try {
114 | return function.apply(t);
115 | } catch (Exception exception) {
116 | throwAsUnchecked(exception);
117 | return null;
118 | }
119 | }
120 |
121 | @SuppressWarnings("unchecked")
122 | private static void throwAsUnchecked(Exception exception) throws E {
123 | throw (E) exception;
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/javatips/lambda/exception/Unchecked.java:
--------------------------------------------------------------------------------
1 | package javatips.lambda.exception;
2 |
3 | import java.util.Objects;
4 | import java.util.function.Function;
5 |
6 | /**
7 | * @author biezhi
8 | * @date 2018/7/24
9 | */
10 | public final class Unchecked {
11 |
12 | @FunctionalInterface
13 | interface ExceptionFunction {
14 | R apply(T t) throws Exception;
15 | }
16 |
17 | public static Function wrap(ExceptionFunction mapper) {
18 | Objects.requireNonNull(mapper);
19 | return t -> {
20 | try {
21 | return mapper.apply(t);
22 | } catch (Exception e) {
23 | throwException(e);
24 | return null;
25 | }
26 | };
27 | }
28 |
29 | public static void throwException(Exception e) throws T {
30 | throw (T) e;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/javatips/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @author biezhi
3 | * @date 2018/7/21
4 | */
5 | package javatips;
--------------------------------------------------------------------------------