文章目录
- Lambda
- Stream流
- 线程(池)
- IO
Lambda
使用前提
- 必须存在一个接口
- 接口中有且只有一个抽象方法
格式 : ( 形式参数 ) -> { 代码块 }
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
// 函数式接口:只有一个抽象方法的接口 加 @FunctionalInterface
@FunctionalInterface
public interface Calculator {
public abstract int calculate(int a,int b);
}
/*
Lambda表达式:简化匿名内部类的代码
语法:
(参数列表) -> {方法体}
参数列表:对应重写方法的参数列表
方法体:对应重写方法的方法体
->:箭头,分割参数列表和方法体
注意:
1. 如果参数列表为空,则可以省略小括号
2. 如果参数列表只有一个参数,则可以省略小括号
3. 如果方法体只有一行代码,则可以省略大括号和return关键字
4. 如果方法体只有一行代码,并且是返回值,则可以省略大括号和return关键字
*/
public class CalculatorTest {
public static void main(String[] args) {
//使用匿名内部类
useCalculator(new Calculator() {
@Override
public int calculate(int a, int b) {
System.out.println(a - b);
return a - b; // -10
}
});
//使用Lambda表达式
useCalculator((a, b) -> {
System.out.println(a + b);
return a + b; // 30
});
//简化Lambda表达式
useCalculator((a, b) -> a * b); // 200
}
public static void useCalculator(Calculator calculator) {
calculator.calculate(10, 20);
}
}
Stream流
获取Stream流
- 创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
- 流水线上的操作。
- 一次操作完毕之后,还可以继续进行其他操作
终结方法
- 一个Stream流只能有一个终结方法
- 是流水线上的最后一个操作
/*
Stream 流
1. Stream 流是 Java 8 的新特性,它允许我们对数据进行一系列的操作,如过滤、映射、排序等。
2. Stream 流的使用可以让代码更加简洁、易读,同时提高代码的执行效率。
3. Stream 流的操作是惰性的,即只有当需要结果时才会执行操作。
4. Stream 流的操作是链式调用的,即可以在一个流上连续调用多个操作。
5. Stream 流的操作是中间操作和终止操作,中间操作不会立即执行,而是返回一个新的流,终止操作会立即执行并返回结果。
6. Stream 流的操作是并行执行的,即可以在多个线程上同时执行操作,提高代码的执行效率。
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StreamTest {
public static void main(String[] args) {
// 集合
List<Integer> list = new ArrayList<>();
// 添加元素
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 使用 stream 流
list.stream().sorted().forEach(num -> System.out.println(num));
list.stream()
.sorted((num1, num2) -> num2 - num1)
.forEach(num -> System.out.println(num));
System.out.println("------------------------");
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "zuo", "shi", "xu", "hebut", "hebust");
list2.stream()
.filter(str -> str.length() > 2)
.filter(str -> str.contains("he"))
.forEach(str -> System.out.println(str));
}
}
线程(池)
线程的两种实现方法
- 继承Thread类
- 实现Runnable接口 (推荐!!!)
- 都需要重写run方法
// 继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("hello" + i);
}
}
}
// 实现Runnable接口
public class MyThread1 implements Runnable {
@Override
public void run() {
for (int i = 500; i < 1000; i++) {
System.out.println("world" + i);
}
}
}
// main方法
public class ThreadTest {
public static void main(String[] args) {
System.out.println("main 方法开始了 ...");
// 方式1 继承 Thread类
// 创建任务类对象
MyThread t1 = new MyThread();
// 启动线程
t1.start();
// 方式2 实现 Runnable接口
// 创建任务类对象
MyThread1 t2 = new MyThread1();
// 创建线程对象
Thread t3 = new Thread(t2);
// 启动线程
t3.start();
for (int i = 1000; i < 1500; i++) {
System.out.println("main 方法执行了 " + i);
}
}
}
线程安全问题 (访问共享数据的问题)
1. 同步代码块
synchronized(锁对象){}
锁对象 可以是任意对象
2. 同步方法
把访问了共享数据的代码抽取出来,放到一个方法中
使用synchronized修饰这个方法
锁对象 就是this
3. 静态同步方法
把访问了共享数据的代码抽取出来,放到一个静态方法中
使用synchronized修饰这个方法
锁对象 就是 类名.class
4. Lock
new ReentrantLock();
lock.lock(); // 上锁
lock.unlock(); // 开锁
import java.util.concurrent.locks.ReentrantLock;
public class Ticket implements Runnable {
private int ticket = 100; //票数
// Lock 推荐
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (ticket <= 0) {
break;
}
if (ticket > 0) {
Thread.sleep(100); // 模拟网络延迟
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
}
ticket--;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); // 永远会执行 不管上面是否有异常 跳出 while也会执行
}
}
}
// // 自定义锁对象
// Object lock = new Object();
//
// @Override
// public void run() {
// while (true) {
// // 同步代码块
// synchronized (lock) {
// if (ticket <= 0) {
// break;
// }
// if (ticket > 0) {
// System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
// }
// ticket--;
// }
// }
// }
// @Override
// public void run() {
// while (true) {
// if (method()){
// break;
// }
// }
// }
//
// // 同步方法
// private synchronized boolean method(){
// if (ticket <= 0) {
// return true;
// }
// if (ticket > 0) {
// System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
// }
// ticket--;
// return false;
// }
}
// main 方法
public class TicketTest {
public static void main(String[] args) {
// 任务对象
Ticket ticket = new Ticket();
// 线程对象 + 线程起名
Thread t1 = new Thread(ticket,"窗口1");
Thread t2 = new Thread(ticket,"窗口2");
Thread t3 = new Thread(ticket,"窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
生产者消费者问题
- 同步锁(synchronized) 解决线程访问共享数据的问题
// 共享数据
public class Resource {
// 不能加 private 类名.属性名 访问不到
static int num = 0; // 一开始桌子上没食物
static final Object lock = new Object(); // 锁对象
}
// 生产者
public class Cooker implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Resource.lock) {
if (Resource.num == 0) {
System.out.println(Thread.currentThread().getName() + "开始做饭");
Resource.num = 1;
Resource.lock.notify(); // 唤醒阻塞进程
} else {
try {
System.out.println(Thread.currentThread().getName() + "阻塞");
Resource.lock.wait(); // 阻塞进程
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
// 消费者
public class Consumer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Resource.lock) {
if (Resource.num == 1) {
System.out.println(Thread.currentThread().getName() + "开始吃饭");
Resource.num = 0;
Resource.lock.notify(); // 唤醒阻塞进程
} else {
try {
System.out.println(Thread.currentThread().getName() + "阻塞");
Resource.lock.wait(); // 阻塞进程
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
// main 方法
public class Test {
public static void main(String[] args) {
// 任务对象
Cooker cooker = new Cooker();
Consumer consumer = new Consumer();
// 线程对象
Thread t1 = new Thread(cooker, "厨师");
Thread t2 = new Thread(consumer, "消费者");
// 启动线程
t1.start();
t2.start();
}
}
线程池
- 通过Executors创建线程池对象
import java.util.concurrent.*;
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 线程池对象 Executors + s
ExecutorService pool = Executors.newFixedThreadPool(3);
// 创建 Callable 类型的线程
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
}
return sum;
}
};
// 执行 Callable 类型的线程
Future<Integer> future = pool.submit(task);
System.out.println("Callable线程执行完毕,结果为:" + future.get());
}
}
IO
复制文件(读文件 + 写文件)三种方法
- 一个字节一个字节读
- 每次读写指定大小的字节
- 采用缓冲区读取(大小自定义) 推荐!!!
// 方法一
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFile {
public static void main(String[] args) {
// 创建字节流对象
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
long beginTime = 0;
long endTime = 0;
try {
beginTime = System.currentTimeMillis();
// 读字节流
fileInputStream = new FileInputStream("day06/file/nuannuan.jpeg");
// 写字节流
fileOutputStream = new FileOutputStream("day06/file/nuanuan2.jpeg", true);
// 读文件 写文件
int data = 0;
while ((data = fileInputStream.read()) != -1) {
fileOutputStream.write(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源 永远会执行 finally里的东西
try {
if (fileInputStream != null) {
fileInputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - beginTime) + "ms"); // 9142ms
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 方法二
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFileBytes {
public static void main(String[] args) {
//1.创建输入输出流对象
FileInputStream fis = null;
FileOutputStream fos = null;
long beginTime = 0;
long endTime = 0;
try {
beginTime = System.currentTimeMillis();
fis = new FileInputStream("day06/file/nuannuan.jpeg");
fos = new FileOutputStream("day06/file/nuannuan1.jpeg");
//2.读写数据
byte[] bytes = new byte[1024]; // 每次读取1K
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len); // 每次写读取到的长度
}
endTime = System.currentTimeMillis();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//3.关闭资源
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
System.out.println("耗时:" + (endTime - beginTime) + "ms"); // 17ms
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 方法三
import java.io.*;
public class CopyFileBuffer {
public static void main(String[] args) {
// 1. 创建源和目标对象
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
long startTime = 0;
long endTime = 0;
// 2.读写文件
try {
startTime = System.currentTimeMillis();
bis = new BufferedInputStream(new FileInputStream("day06/file/nuannuan.jpeg"), 1024 * 80);
bos = new BufferedOutputStream(new FileOutputStream("day06/file/nuannuan1.jpeg"), 1024 * 80);
int len = 0;
while ((len = bis.read()) != -1) {
bos.write(len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
try {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime - startTime) + "ms"); //152ms
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字符流 = 字节流 + 编码表读文件