├── .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; --------------------------------------------------------------------------------