Java8新特性
1. Lambda表达式
1.1 基本写法
正常遍历
for (int i = 0; i < fruits.size(); i++) {
Fruit f = fruits.get(i);
System.out.println(f.getName());
}
Lambda
fruits.forEach(f -> {
System.out.println(f.getName());
});
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JjK6Zq0X-1632358773638)(https://style.youkeda.com/img/ham/course/j5/j5-1-2-1.svg)]
Lambda表达式在功能上等同于一个匿名方法
public void unknown(f) {
System.out.println(f.getName());
}
在Lambda中引用本地变量必须是最终变量或实际上的最终变量
1.2 双冒号操作符::
使用::
时,系统每次取得的变量会自动作为参数传递给方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oGeDTnn-1632358773641)(https://style.youkeda.com/img/ham/course/j5/j5-1-5-1.svg)]
- 静态方法调用
- 非静态方法调用
- 多参数
- 父类方法
2. Stream API
2.1 创建流
-
直接创建
import java.util.stream.Stream; Stream<String> stream = Stream.of("苹果", "哈密瓜", "香蕉", "西瓜", "火龙果");
-
由数组转化
String[] fruitArray = new String[] {"苹果", "哈密瓜", "香蕉", "西瓜", "火龙果"}; Stream<String> stream = Stream.of(fruitArray);
-
由集合转化
List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("哈密瓜");
fruits.add("香蕉");
fruits.add("西瓜");
fruits.add("火龙果");
Stream<String> stream = fruits.stream();
2.2 迭代流
Stream<String> stream = Stream.of("苹果", "哈密瓜", "香蕉", "西瓜", "火龙果");
stream.forEach(System.out::println);
这里的forEach()与前边Lambda的forEach()是两种东西
2.3 流数据过滤
filter()
方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ARptA8qy-1632358773644)(https://style.youkeda.com/img/ham/course/j5/j5-2-3-2.svg)]
2.4 流设计思想
数据流的操作过程,可以看作一个管道,管道由多个节点组成,每个节点完成一个操作。
数据流输入这个管道, 按照顺序经过各个节点。
2.5 流数据映射
map()
方法
map()方法常称为映射,就是用新的元素替换掉流中原来相同位置的元素。相当于每个对象都经历一次转换。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VcI3g0NX-1632358773647)(https://style.youkeda.com/img/ham/course/j5/j5-2-5-1.svg)]
2.6 流数据排序
sorted()方法
students.stream()
// 实现升序排序
.sorted((student1, student2) -> {
return student1.getRollNo() - student2.getRollNo();
})
.forEach(System.out::println);
2.7 流数据摘取
limit()
方法的作用是返回流的前n个元素
3 并行数据
3.1 流合并
完成从1到10 的和
import java.util.Arrays;
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.stream()
.reduce((a, b) -> a + b)
.get();
System.out.println("1-10求和 : " + sum);
reduce( )方法
的作用是合并了所有的元素,终止计算出一个结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6ioItyV-1632358773652)(https://style.youkeda.com/img/ham/course/j5/j5-3-1-1.svg)]
3.2 流收集
collect()
方法的作用就是收集元素
Collectors.toList()
是一个静态方法,作为参数告诉collect()
方法存入一个List()
集合。、
3.3 并行流
串行的工作方式很难进行优化,无法发挥多核CPU和多线程的优势。
4 设计模式
4.1 单例设计模式
先实例化一个对象,然后封装构造方法,暴露一个公开方法获取实例
public class ClassMaster {
private String id;
// 班主任名称
private String name;
private String gender;
// 唯一实例
private static ClassMaster instance = new ClassMaster();
private ClassMaster() {
}
// 外部类可以通过这个方法访问唯一的实例
public static ClassMaster getInstance() {
return instance;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLGTx4bA-1632358773653)(https://style.youkeda.com/img/ham/course/j5/j5-4-2-1.svg)]
Spring中的单例
@Autowired
注解
4.2 简单工厂模式
根据不同条件创建不同对象
实现简单工厂步骤:
- 从具体的产品类抽象出接口,工厂应该生产一种产品而不是一个产品
- 把生产实例对象的过程,收拢到工厂类中去实现
简单工厂中抽象类的用法
- 存放公共属性和方法
- 每个实现类存放特有的属性和方法
4.3 抽象工厂模式
对于一批、多种类型的对象需要创建的场景,使用抽象公厂模式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8ioVJFV-1632358773655)(https://style.youkeda.com/img/ham/course/j5/j5-4-4-1.svg)]
-
工厂接口(SnackFactory)
规定工厂应该提供什么样的产品
public interface SnacksFactory { // 取得水果 public Fruit getFruit(Customer customer); // 取得饮料 public Drink getDrink(Customer customer); }
-
工厂的工厂(SnacksFactoryBuilder)
工厂用来生产产品实例,
SnacksFactoryBuilder
用来生成工厂实例
public class SnacksFactoryBuilder {
public SnacksFactory buildFactory(String choice) {
if (choice.equalsIgnoreCase("fruit")) {
return new FruitFactory();
} else if (choice.equalsIgnoreCase("drink")) {
return new DrinkFactory();
}
return null;
}
}
不提倡在工厂中定义
static
方法的一个原因在使用
Spring
框架时,可以为类加上@Compoent
注解,让框架管理实例这样在需要用到实例的时候只需使用
@AutoWired
注解让框架自动注入实例即可
4.4 观察者模式
适合订阅/通知的场景
发送通知,继承Observable
类
import java.util.Observable;
public class WeatherData extends Observable {
/**
* 一个城市的气温在某个时刻发生了变化
*/
public void changeTemp(String time, String temp) {
if(time == null || temp == null) {
// 输入数据为空是有问题的,不处理
return;
}
// 与原数据不同,说明发生了变化
if(!time.equals(this.time) || !temp.equals(this.temp)) {
// 标记变化
super.setChanged();
this.time = time;
this.temp = temp;
// 发出通知,参数是额外的信息
super.notifyObservers("温度变化已通知");
}
}
}
接收通知,实现Observer
接口
import java.util.Observable;
import java.util.Observer;
public class WeatherObserver implements Observer {
private String name;
@Override
public void update(Observable o, Object arg) {
System.out.print(this.name + "观察到天气变化为:");
System.out.print(o.toString());
System.out.println(" " + arg);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HpkPaqYR-1632358773657)(https://style.youkeda.com/img/ham/course/j5/j5-4-5-1.svg)]
5 并发编程
5.1 多线程Thread
构造线程类
- 通过继承
Thread
类构造线程类
public class Person extends Thread {
}
- 通过实现
Runnable
接口实现接口
public class Person implements Runnable {
}
通过实现接口构造的类,需要包装在Thread的实现类中
public class Bank {
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("张三");
Thread thread1 = new Thread(person1);
thread1.start();
}
}
5.2 线程安全
同步锁synchronized
: 同一时刻只能有一个线程进入同步方法或者同步语句块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rx6DXBjP-1632358773658)(https://style.youkeda.com/img/ham/course/j5/j5-5-4-1.svg)]
使用了synchronized
的方法意味着满足了两个线程安全的特性
- 原子性:方法全部执行并且执行的过程不会被任何因素打扰。
- 可见性:当多个线程访问同一个变量的时候,一个线程修改了这个变量的值,其他线程能力及看得到修改的值
但同时,为了实现这两个特性:也要付出代价:性能降低
因此,synchronized
比较适合的场景是:
- 写操作的场景。
- 降低锁的粒度,把最关键的部位抽象为同步方法
5.3 悲观锁和乐观锁
悲观锁:
适合写数据比重更大的应用场景。一般来说写数据的整体消耗时间更长些
乐观锁:
不适合多条数据需要修改,以及多个操作整体顺序要求比较严格的场景
AtomicInteger
相当于一个整数,该类提供了不需要使用同步就能保证原子性的方法
例:decrementAndGet()
5.4 并发容器
适用场景:多个任务有前后的顺序,但后继的任务不需要等待前置任务全部处理完,而是每个前置执行完自动执行对应后置。
CompletableFuture
是一个异步任务编排、调度框架,以更优雅的方式实现组合式编程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oETHHuq7-1632358773661)(https://style.youkeda.com/img/ham/course/j5/j5-5-7-1.svg)]
5.5 线程池
线程池:就像一个里边装满了线程的池子,线程可以被复用,随用随取。
线程池的大小并不是无限的,过剩的任务需要排队才能继续执行。
创建线程池的核心代码:
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import java.util.concurrent.*;
public class StudentIDTest {
// 线程工厂
private static final ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder()
.namingPattern("studentReg-pool-%d")
.daemon(true)
.build();
// 等待队列
private static final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(1024);
// 线程池服务
private static final ThreadPoolExecutor EXECUTOR_SERVICE = new ThreadPoolExecutor(
20,
200,
30,
TimeUnit.SECONDS,
workQueue,
namedThreadFactory,
new ThreadPoolExecutor.AbortPolicy()
);
public static void main(String[] args) {
}
}
BasicThreadFactory
需要依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
BasicThreadFactory
需要依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>