一、Java运行环境
1.1 编译运行
javac 类名.class/类名.java
java 类名
二、Java数据结构
2.1 命名规范
内容 | 规范 |
---|---|
类名 | 大写字母开头,驼峰命名 |
变量 | 小写字母开头,驼峰命名 |
常量 | 大写字母,_ 分割 |
2.2 main函数
main函数的退出码为0,表示成功的运行了程序
args:命令行参数
java Message -g cruel world 以命令行方式启动程序
则args参数为:
args[0]:-g
args[1]:cruel
args[2]:world
/**
* 采用严格的浮点计算
* @param args
*/
public static strictfp void main(String[] args) {
}
2.3 注释
单行://
多行:/* */
文档:/** */
文档注释使用(可指定存储位置)
javadoc -encoding UTF-8 User.java
2.4 整型
类型 | 存储需求(字节) | 注意 |
---|---|---|
int | 4 | |
short | 2 | |
long | 8 | 加后缀l或L |
byte | 1 |
二进制:0b、0B
八进制:前缀0
十六机制:0x、0X
2.5 浮点
类型 | 存储需求(字节) | 注意 |
---|---|---|
float | 4 | 有效位6-7,加后缀f或F |
double | 8 | 有效位15 |
浮点数不适用于金融计算。二进制系统无法精确的表示,会存在舍入误差,需要使用BigDecimal类解决
System.out.println(2.0-1.1);
==>0.8999999999999999
2.6 char
使用单引号括起来,可以包含特殊的转义字符
'a' '\u0008' '\u000a'
2.7 boolean
fasle和true,整型值和布尔值不能转换
2.8 变量
必须显示的初始化变量,否则会报错
boolean test = false;
System.out.println(test);
2.9 常量
只能被赋值一次
public class Constant {
public static final int TEST = 1; // 类常量:可以在不同类的多个方法使用
public final int TEST_2 = 2; // 只允许在本类中使用的常量
}
类常量调用
public void test(){
int test = Constant.TEST;
}
2.10 枚举
/**
* 声明枚举类
* 可以为枚举类添加构造器、方法、字段
*/
public enum Enum {
SMALL("小"),MEDIUM("中"),LARGE("大"); // 类似于一个个构造器
private String size;
Enum(String size){
this.size = size;
}
public String getSize(){
return size;
}
}
@Test
public void testEnum(){
System.out.println(Enum.MEDIUM.getSize()); // 获取常量值
Enum large = Enum.valueOf(Enum.class, "LARGE"); // 返回给定名字指定类型的常量名
System.out.println(large);
}
2.11 数值类型转换
两个操作数在运算的时候会自动转为精度高一级的类型计算
对于整数+浮点数
- 有一个操作数是double,转为double
- 有一个操作数为float,转为float
- 两个都是int,转为int
2.12 强制类型转换
int x = (int)3.99
==>3 // 截取小数部分
@Test
public void testCast(){
System.out.println(Math.round(9.998)); // 四舍五入
}
==>10
2.13 String类型
String类对象是不可变的,Java将字符串存入公共存储池中,变量指向存池中字符串的位置,复制变量就可以将多个变量指向相同的位置。
字符串类型在堆中分配,且具有自动垃圾回收机制,不会导致内存泄露。
禁止使用 == 对比,因为如果放在同一位置上是相等的,如果有多个字符串副本放在不同位置上,就会存在bug
注意:null不是空串,str != null
判断
常用方法
@Test
public void testString(){
String str = "Hello";
// 截取字符串
System.out.println("str.substring(0, 3) = " + str.substring(0, 3)); // 索引 0 <= index < 3 ==> Hel
// 字符串拼接
System.out.println("Hello" + "Java"); // ==> HelloJava
// 字符串相等
String str2 = "hello";
System.out.println(str.equals(str2)); // 将常量放第一个位置,避免空指针异常
System.out.println(str.equalsIgnoreCase(str2)); // 忽略大小写对比
// StringAPI
System.out.println(str.charAt(0)); // 获取为0的索引
System.out.println(str.isEmpty()); // 判空
System.out.println(str.startsWith("Hel")); // 以 Hel 开头返回boolean
System.out.println(str.endsWith("lo")); // 以 lo 结尾返回boolean
System.out.println(str.length()); // 字符串的长度
System.out.println(str.replace('H', 'h')); // 将旧字符替换成新字符
System.out.println(str.toLowerCase()); // 变成小写
System.out.println(str.toUpperCase()); // 变成大写
System.out.println(str.trim()); // 返回去除首尾空格的字符串
System.out.println(String.join("-", "a","b")); // a和b之间用 - 连接 ==> a-b
System.out.println(str.indexOf('H')); // 返回 H 第一次出现的位置
System.out.println(str.indexOf('l',3)); // 返回 l 从索引3开始出现的l的第一次的索引值
}
2.14 字符串构建器
解决频繁拼接字符串频繁的创建String对象的带来的耗时和浪费空间的问题
StringBuilder:单线程使用
StringBuffer:多线程使用
@Test
public void testStringBuilder(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abc");
stringBuilder.append("cd");
System.out.println("stringBuilder = " + stringBuilder.toString());
}
@Test
public void testStringBuilder(){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abc");
stringBuilder.append("cd");
System.out.println("stringBuilder = " + stringBuilder.toString());
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abc");
stringBuffer.append("cd");
System.out.println("stringBuffer.toString() = " + stringBuffer.toString());
}
2.15 大数
解决基本的整数和浮点数精度不能够满足需求
@Test
public void testBigDecimal(){
BigDecimal value1 = new BigDecimal("2.00");
BigDecimal value2 = new BigDecimal("1.99");
double value3 = 0.00;
BigDecimal value3ForBigDecimal = BigDecimal.valueOf(value3); // 基本类型转换为大数类型
BigDecimal add = value1.add(value2);
BigDecimal subtract = value1.subtract(value2);
// BigDecimal divide = value1.divide(value2);
int result = value1.compareTo(value2); // 相等返回0,如果v1<v2返回负,反之为正
System.out.println(add);
System.out.println(subtract);
System.out.println(result);
}
2.16 数组
@Test
public void testArray() {
int[] a = new int[100]; // 初始化空间
int[] array = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
// 增强for遍历
for (int item : array) {
System.out.println(item); // 无需 array[item] 增强for每次遍历的是一个元素
}
System.out.println(Arrays.toString(array)); // 数组转为字符串更方便地看到遍历结果
// 数组拷贝
String[] str = {"apple","banana"};
String[] newStr = Arrays.copyOf(str, str.length);
System.out.println(Arrays.toString(newStr));
System.out.println(Arrays.toString(str));
}
2.17 ArraysAPI
@Test
public void testArraysAPI(){
int[] array = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
Arrays.sort(array); // 使用优化后的快速排序算法对数组从小到大排序
System.out.println(Arrays.toString(array)); // 数组转换为字符串
int[] copyOf = Arrays.copyOf(array, array.length);// 声明数组和数组长度返回新的拷贝后的数组
System.out.println(Arrays.equals(copyOf, array)); // 判断数组中元素是否相等
Arrays.fill(copyOf, -1); // 将所有元素设置为某个值
System.out.println(Arrays.toString(copyOf));
}
三、面向对象
3.1 LocalDate类的使用
@Test
public void testLocalDate(){
LocalDate now = LocalDate.now(); // 获取当前年月日 构造对象
System.out.println(now); // ==> 2022-08-24
LocalDate date = LocalDate.of(2021, 12, 1); // 构造对象
System.out.println(date);
// 分别获取年月日
System.out.println(date.getYear());
System.out.println(date.getMonthValue());
System.out.println(date.getDayOfMonth());
System.out.println(now.getDayOfWeek()); // 得到当前日期是星期几 ==>WEDNESDAY
System.out.println(now.plusDays(8)); // 获取当前日期之后8天的日期 ==>2022-09-01
System.out.println(now.minusDays(8)); // 获取当前日期之前8天的日期
}
3.2 null
null:表示没有引用任何对象,出现于对象类型中,基本类型不会出现null值
3.3 警告
如果自定义类需要返回一个对象的引用,会改变这个对象的私有状态
因为这个时候均引用了同一对象
可以使用clone方法解决
3.4 final
作用于类:阻止继承
作用于方法:最终方法,子类不能重写该方法
作用于属性:不能修改值
注意:对于一个对象使用了final修饰,可以改变里面的值,但改变不了对象的引用
3.5 static
作用于方法、属性
可以使用对象调用静态方法,但还是建议使用类名调用方法
public static final int TEST = 1; // 类常量:可以在不同类的多个方法使用
public static User testStatic(){
return new User();
}
3.6 重载
同一类下,相同名字不同参数
// 重载
/**
* 空参构造器
*/
public User(){
}
/**
* 有参构造
*/
public User(String username){
this.username = username;
}
public User(String username,String password){
this.username = username;
this.password = password;
}
/**
* 空参构造器
*/
public User(){
this("调用另一个构造器","1234"); // 调用了本类其他构造器
}
3.7 初始化代码块
// 初始化代码块,只要类创建成对象就会执行该代码块
{
flag = true;
}
// 初始化静态属性
static {
str = "调用了静态代码块,初始静态属性";
}
静态代码块随类的创建而初始化
普通代码块需要创建对象才会生成
3.8 包、类
完全限定名:com.wwj.java.User 包含类名
静态导入:import static java.lang.System.*
使用静态方法和属性的时候无需添加类名前缀
3.9 包访问
private:标记本类使用
public:可以任意类使用,不能再各个模块使用
default:同一个包内访问
protected:对本包和所有子类可见
3.10 继承
/**
* 继承了People为子类,People可以称为父类、超类、基类
*/
public class Man extends People{
public Man(){
super("调用父类构造","男"); // 调用父类构造器
}
public String getParentWork(){
return super.work(); // 调用父类方法
}
3.11 多态
@Test
public void testDuoTai(){
// 运行看右边,编译看左边
People man = new Man();
System.out.println("man.work() = " + man.work());
}
编译父类所有的方法和属性,对象只能获取父类的方法和属性如果子类有重写就调用子类的方法和属性
3.12 判断实例对象类型
System.out.println(man instanceof Man);
子类可以转超类
超类转子类需要上述检查
3.13 抽象类
抽象类可以包含抽象方法、字段、具体方法、构造器
3.14 hashCode
Object类中hashCode由对象的存储地址得出
每个对象都有一个默认的hashCode,不同对象的hashCode基本不会相同
3.15 自动装拆箱
@Test
public void testAutoBox(){
Integer n = 3; // 自动装箱
int a = n; // 自动拆箱
}
System.out.println("Integer.parseInt(\"1\") = " + Integer.parseInt("1")); // 转换为整型
Integer integer = Integer.valueOf(1); // 转换为包装类型
3.16 可变参数
public void param(String name,String ... param){
System.out.println(Arrays.toString(param)); // 此时这个param是一个字符串数组
}
3.17 反射(了解)
public class Reflect {
public static void main(String[] args) throws Exception {
User user = new User();
// 获取Class方式1
Class<? extends User> userClass1 = user.getClass();
// 获取Class方式2
Class<?> userClass2 = Class.forName("com.wwj.java.MyObject.User");
// 获取Class方式3
Class<User> userClass3 = User.class;
User user2 = userClass1.getConstructor().newInstance(); // 反射通过无参构造器创建实例对象
System.out.println(user2);
Class<People> peopleClass = People.class;
Field[] fields = peopleClass.getDeclaredFields();
for (Field field : fields) {
/*
返回属性字段
private java.lang.String com.wwj.java.MyObject.People.name
private java.lang.String com.wwj.java.MyObject.People.gender
*/
System.out.println(field);
}
Method[] declaredMethods = peopleClass.getDeclaredMethods(); // 返回这个类和接口的全部方法
for (Method declaredMethod : declaredMethods) {
/*
public boolean com.wwj.java.MyObject.People.equals(java.lang.Object)
public java.lang.String com.wwj.java.MyObject.People.toString()
public int com.wwj.java.MyObject.People.hashCode()
public java.lang.String com.wwj.java.MyObject.People.getName()
public void com.wwj.java.MyObject.People.setName(java.lang.String)
public java.lang.String com.wwj.java.MyObject.People.work()
public java.lang.String com.wwj.java.MyObject.People.getGender()
public void com.wwj.java.MyObject.People.setGender(java.lang.String)
protected boolean com.wwj.java.MyObject.People.canEqual(java.lang.Object)
*/
System.out.println(declaredMethod);
}
// 获取全包名
Package aPackage = peopleClass.getPackage();
System.out.println(aPackage);
Field name = peopleClass.getDeclaredField("name"); // 获取name的Field
People people = new People("www", "nan");
name.setAccessible(true); // 覆盖Java访问控制
Object o = name.get(people); // 利用反射获取实例对象的属性值
System.out.println(o);
Method work = peopleClass.getMethod("work"); // 获取work方法用实例对象执行
String result = (String) work.invoke(people);
System.out.println(result);
}
}
3.18 接口
泛型接口
public interface MyInterface<T> {
int testMethod(T other);
}
如果实现接口指定了泛型传入的形参必须是指定的类型
public class testInterface implements MyInterface<People>{
@Override
public int testMethod(People other) {
return 0;
}
}
接口所有方法都是自动public
发生方法同名冲突,遵循类优先原则
/**
* 默认方法,可以被实现类所覆盖,也可以调用其他的接口方法
* @param other 泛型
* @return 整型
*/
default int testDefault(T other){
return testMethod(other);
}
3.19 lambda表达式
class TestMain {
public static void main(String[] args) {
Worker[] workers = new Worker[3];
Worker worker1 = new Worker(1,11);
Worker worker2 = new Worker(2,22);
Worker worker3 = new Worker(3,33);
workers[0] = worker1;
workers[1] = worker2;
workers[2] = worker3;
// lambda表达式实现自定义比较器
Arrays.sort(workers,(first,second) -> second.getAge() - first.getAge());
for (Worker worker : workers) {
System.out.println(worker);
}
}
}
3.20 方法引用
只能替换单方法的Lambda表达式
类名::静态方法
对象::成员方法
类名::成员方法
类名::new(构造方法)
3.21 DateAPI使用
@Test
public void testDate() throws InterruptedException {
Date date = new Date(); // 构造参数:1970 1 1 加的毫秒数
System.out.println(date.toString()); // 获取当前日期时间
// 日期比较:使用方法 before(),after() 和 equals()。例如,一个月的12号比18号早,则 new Date(99, 2, 12).before(new Date (99, 2, 18)) 返回true。
// 使用getTime比较日期
date.compareTo(date); // 日期比较
// 日期格式化
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
System.out.println(format.format(date));
// 测量执行方法时间
long start = System.currentTimeMillis();
System.out.println("业务方法");
Thread.sleep(300);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start));
Calendar c = Calendar.getInstance();
System.out.println(c);
c.set(2009, Calendar.JUNE, 12); // 年 月 日
c.add(Calendar.DATE, 10); // 当前日期的天数 + 10天
// 获得年份
int year = c.get(Calendar.YEAR);
// 获得月份
int month = c.get(Calendar.MONTH) + 1;
// 获得日期
int date2 = c.get(Calendar.DATE);
// 获得小时
int hour = c.get(Calendar.HOUR_OF_DAY);
// 获得分钟
int minute = c.get(Calendar.MINUTE);
// 获得秒
int second = c.get(Calendar.SECOND);
// 获得星期几(注意(这个与Date类是不同的):1代表星期日、2代表星期1、3代表星期二,以此类推)
int day = c.get(Calendar.DAY_OF_WEEK);
System.out.println(year);
System.out.println(month);
System.out.println(date2);
System.out.println(hour);
System.out.println(minute);
System.out.println(second);
System.out.println(day);
}
3.22 正则基本使用
@Test
public void testRegex(){
String content = "I am noob from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content); // 正则表达式,内容
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch);
}
3.23 IO流
输入流用于从源读取数据,输出流用于向目标写数据。
读取控制台内容
// 读取键盘的输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// char c ;
String c;
do {
// c = (char) br.read(); // 读取每个字符
c = (String) br.readLine(); // 读取字符串
System.out.println("读取到的内容:"+c);
}while (!c.equals("q"));
字符流
@Test
public void fileIO2() throws Exception{
File file = new File("C:\\CodeStudy\\text.txt");
boolean flag = file.createNewFile();
System.out.println("创建文件:"+ (flag ? "成功":"失败"));
FileWriter writer = new FileWriter(file);
writer.write("hello word !");
writer.flush(); // 刷新暂存区
writer.close();
FileReader reader = new FileReader(file);
char[] a = new char[50]; // 准备缓存区
int read = reader.read(a);// 将文件读取到缓存区中
System.out.println("===>"+read); // 返回字符
for (char c : a){
System.out.println(c);
}
reader.close();
}
字节流
public static void main(String[] args) throws IOException {
//输入文件目录
String srcFilePath = "D:\\io_test\\加菲猫.jpg";
//输出文件目录(拷贝的路径)
String destFilePath = "D:\\io_test\\加菲猫2.jpg";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//输入流,传入路径
fileInputStream = new FileInputStream(srcFilePath);
//输出流
fileOutputStream = new FileOutputStream(destFilePath);
byte[] bytes = new byte[1024];
try {
int count = 0;
//如果不等于-1说明还没有读取完成,要继续读取
while((count = fileInputStream.read(bytes)) != -1){
//还有内容要读取,然后从0开始读取,上面count有读了多少个,那么就写多少个
fileOutputStream.write(bytes,0,count);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
//用完之后一定要关闭流,但是得判断不是空的时候才需要去关闭流
if(fileInputStream != null){
fileInputStream.close();
}
if(fileOutputStream != null){
fileOutputStream.close();
}
}
}
带缓冲区的字节流
public class IoDemo5 {
public static void main(String[] args) {
//输入文件目录
String srcFilePath = "D:\\io_test\\加菲猫.jpg";
//输出文件目录(拷贝的路径)
String destFilePath = "D:\\io_test\\加菲猫3.jpg";
try {
//因为带有缓存区的是基于原始的类进行操作的
BufferedInputStream bufferedInputStream =
new BufferedInputStream(new FileInputStream(srcFilePath));
BufferedOutputStream bufferedOutputStream =
new BufferedOutputStream(new FileOutputStream(destFilePath));
{
byte[] bytes = new byte[1024];
int count = 0;
while ((count = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,count);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3.24 自定义异常类
public class MyException extends Exception{
/**
* public Throwable(String message) {
* fillInStackTrace();
* detailMessage = message;
* }
*/
// 重写构造器
public MyException(String message){
System.out.println(message);
}
}
3.25 集合
ArrayList
@Test
public void testArrayListUsed(){
// ArrayList 继承了 AbstractList ,并实现了 List 接口。
ArrayList<People> arrayList = new ArrayList<>();
arrayList.add(new People("wwj", "nan"));
People people = arrayList.get(0); // 访问元素
arrayList.set(0, new People("www","weww")); // 修改对应索引的值
arrayList.remove(0); // 移除元素
int size = arrayList.size(); // 计算大小
}
LinkedList
@Test
public void testLinkedList(){
/**
* 你需要通过循环迭代来访问列表中的某些元素。
* 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
*/
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("Google");
linkedList.add("Runoob");
linkedList.add("Taobao");
linkedList.add("Weibo");
// 使用 addFirst() 在头部添加元素
linkedList.addFirst("Wiki");
// 使用 addLast() 在尾部添加元素
linkedList.addLast("Wiki");
// 使用 removeFirst() 移除头部元素
linkedList.removeFirst();
// 使用 removeLast() 移除尾部元素
linkedList.removeLast();
// 使用 getFirst() 获取头部元素
System.out.println(linkedList.getFirst());
// 使用 getLast() 获取尾部元素
System.out.println(linkedList.getLast());
}
hashSet
/**
* HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
* HashSet 允许有 null 值。
* HashSet 是无序的,即不会记录插入的顺序。
* HashSet 不是线程安全的
*/
@Test
public void testHashSet(){
HashSet<Integer> hashSet = new HashSet<>();
hashSet.add(1);
hashSet.add(2);
hashSet.add(3);
hashSet.add(1);
System.out.println(hashSet);
System.out.println(hashSet.contains(1)); // 集合是否包含 xxx
hashSet.remove(1);
}
hashMap
/**
* HashMap 是无序的,即不会记录插入的顺序。
* HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
* HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
*/
@Test
public void testHashMap(){
HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("1", "v1");
hashMap.put("2", "v2");
hashMap.put("3", "v3");
// String s = hashMap.get("1");
// String remove = hashMap.remove("1");
// 函数式接口得带HashMap
hashMap.forEach((key,value) -> {
System.out.println("key:"+key+"="+"value"+value);
});
}
Iterator
/**
* Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。
*
*/
@Test
public void testIterator(){
// 创建集合
ArrayList<String> sites = new ArrayList<String>();
sites.add("Google");
sites.add("Runoob");
sites.add("Taobao");
sites.add("Zhihu");
Iterator<String> iterator = sites.iterator(); // 获取迭代器
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
3.26 泛型
-
E - Element (在集合中使用,因为集合中存放的是元素)
-
T - Type(Java 类)
-
K - Key(键)
-
V - Value(值)
-
N - Number(数值类型)
-
? - 表示不确定的 java 类型
public class ArrayList<E> extends AbstractList<E>
泛型类
public class Box<T> {
类型通配符一般是使用 ? 代替具体的类型参数。
@Test
public void testFanXin(List<?> list){
// 此时形参代表可以传入不同类型的集合List<String>,List<Integer>
// public static void getUperNumber(List<? extends Number> data) 如此定义就是通配符泛型值接受Number及其下层子类类型。
}
类型通配符下限通过形如 List<? super Number> 来定义,表示类型只能接受 Number 及其上层父类类型,如 Object 类型的实例。
3.27 多线程
package com.wwj.java.myThread;
import java.util.concurrent.*;
/**
* 继承Thread创建线程
*/
public class MyThread extends Thread {
@Override
public void run() {
// System.out.println("当前线程:"+Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
}
}
/**
* 实现Runnable接口创建线程
*/
class MyThead02 implements Runnable {
@Override
public void run() {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
}
}
/**
* Callable创建线程(可以返回值)
*/
class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int i = 10 / 2;
return i;
}
}
class testThread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread thread01 = new MyThread(); // 继承Thread创建线程
thread01.start();
MyThead02 myThead02 = new MyThead02(); // 实现Runnable创建线程
new Thread(myThead02).start();
// callable 带有返回值
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
Integer integer = futureTask.get(); // 等待异步方法执行完成打印结果
System.out.println("callable创建线程返回的结果:" + integer);
// 线程池创建
/**
* @Param corePoolSize: 核心线程数(一直存在除非设置超时)
* @Param maximumPoolSize:最大线程数量
* @Param keepAliveTime:最大线程数量-核心线程数):存活时间,当前线程数量大于核心数量,释放空闲的线程,只要线程空闲时间大于指定的存活时间
* @Param unit:时间单位
* @Param workQueue::阻塞队列,如果任务有很多,就会将目前多的任务放在队列里只要有线程空闲就会去队列里取出新的任务
* @Param threadFactory:线程创建工厂
* @Param handler:如果队列满了,按照指定的拒绝策略拒绝执行任务
*/
ExecutorService threadPool = new ThreadPoolExecutor(
20,
100,
10L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(10000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
// 异步任务(无返回值)
CompletableFuture<Void> future01 = CompletableFuture.runAsync(() -> {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
}, threadPool);
// 异步任务(有返回值)
CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
return i;
}, threadPool);
System.out.println("future02异步任务返回值:" + future02.get());
// 异步任务链
CompletableFuture<Integer> future03 = CompletableFuture.supplyAsync(() -> {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
return i;
}, threadPool).whenComplete((result, exception) -> {
// 可以接收异常和结果
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "接收结果" + result
+ "\t" + "异常:" + exception);
}).exceptionally(throwable -> {
// 异常返回类型
return 10;
});
// 异步任务链(同时处理异常和结果)
CompletableFuture<Integer> future04 = CompletableFuture.supplyAsync(() -> {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
return i;
}, threadPool).handle((result, exception) -> { // 能够同时处理异常和正确返回
if (result != null) {
return result * 2;
} else {
return 0;
}
});
// 异步任务链(可以接收结果还可以返回数据)
CompletableFuture<String> future05 = CompletableFuture.supplyAsync(() -> {
int i = 10 / 2;
System.out.println("当前线程" + Thread.currentThread().getId() + "\t" + "运行结果" + i);
return i;
}, threadPool).thenApplyAsync(res -> { // 又可以接收返回值又可以返回数据
System.out.println("start2..." + res);
return "接收到的结果返回" + res;
}, threadPool);
System.out.println(future05.get());
// 异步任务组合操作(两个任务均完成)
future01.runAfterBoth(future02, () -> { // 两个任务均完成执行的操作(无返回值不接收结果)
System.out.println("两个任务均完成");
});
future01.thenAcceptBoth(future02, (f1,f2) -> { // 接收两个异步任务的返回结果
System.out.println("接收异步任务返回值"+ f1 + f2);
});
future01.thenCombineAsync(future02, (f1,f2) -> {
System.out.println("接收返回值"+ f1 + f2);
return f1 + "" + f2;
},threadPool);
// 两个任务有一个完成
future01.runAfterEitherAsync(future02, ()->{
System.out.println("任务3");
},threadPool);
future03.acceptEitherAsync(future02, (res)->{
},threadPool);
future02.applyToEither(future03, (res) -> {
System.out.println(res);
return res;
});
CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02);
allOf.get(); // 等待所有结果完成(阻塞)
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02);
anyOf.get(); // 有一个成功就不阻塞
}
}