Java新特性

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)]

  1. 静态方法调用
  2. 非静态方法调用
  3. 多参数
  4. 父类方法

2. Stream API

2.1 创建流

  1. 直接创建

    import java.util.stream.Stream;
    
    Stream<String> stream = Stream.of("苹果", "哈密瓜", "香蕉", "西瓜", "火龙果");
    
  2. 由数组转化

    String[] fruitArray = new String[] {"苹果", "哈密瓜", "香蕉", "西瓜", "火龙果"};
    Stream<String> stream = Stream.of(fruitArray);
    
  3. 由集合转化

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 简单工厂模式

根据不同条件创建不同对象

实现简单工厂步骤:

  1. 从具体的产品类抽象出接口,工厂应该生产一种产品而不是一个产品
  2. 把生产实例对象的过程,收拢到工厂类中去实现

简单工厂中抽象类的用法

  1. 存放公共属性和方法
  2. 每个实现类存放特有的属性和方法

4.3 抽象工厂模式

对于一批、多种类型的对象需要创建的场景,使用抽象公厂模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J8ioVJFV-1632358773655)(https://style.youkeda.com/img/ham/course/j5/j5-4-4-1.svg)]

  1. 工厂接口(SnackFactory)

    规定工厂应该提供什么样的产品

    public interface SnacksFactory {
        // 取得水果
        public Fruit getFruit(Customer customer);
        // 取得饮料
        public Drink getDrink(Customer customer);
    }
    
  2. 工厂的工厂(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

构造线程类

  1. 通过继承 Thread 类构造线程类
public class Person extends Thread {

}
  1. 通过实现 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的方法意味着满足了两个线程安全的特性

  1. 原子性:方法全部执行并且执行的过程不会被任何因素打扰。
  2. 可见性:当多个线程访问同一个变量的时候,一个线程修改了这个变量的值,其他线程能力及看得到修改的值

但同时,为了实现这两个特性:也要付出代价:性能降低

因此,synchronized比较适合的场景是:

  1. 写操作的场景。
  2. 降低锁的粒度,把最关键的部位抽象为同步方法

5.3 悲观锁和乐观锁

悲观锁

适合写数据比重更大的应用场景。一般来说写数据的整体消耗时间更长些

乐观锁

不适合多条数据需要修改,以及多个操作整体顺序要求比较严格的场景

AtomicInteger相当于一个整数,该类提供了不需要使用同步就能保证原子性的方法

例:decrementAndGet()

img

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liwan95

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值