JAVA学习 API_day08(线程池, Lambda表达式, 注释, 可变长参数)

线程池, Lambda表达式, 注释, 可变长参数

  • 1. 线程池
    • 1.线程池: Executors 工厂类中的方法
    • 2.Callable接口
  • 2. Lambda表达式
  • 3. 注解
  • 4. 单元测试
  • 5. 可变长参数

1. 线程池

1.线程池: Executors 工厂类中的方法

构造方法----------------------------------------------------------
newCachedThreadPool(): 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
newFixedThreadPool(int nThreads): 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。
newScheduledThreadPool(int corePoolSize): 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
newSingleThreadExecutor(): 创建一个使用从无界队列运行的单个工作线程的执行程序。
构造方法----------------------------------------------------------

线程池执行任务的API:
1.submit(Runnable/Callable)
2.execute(Runnable)
代码实现:newCachedThreadPool()

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Pool {
     
    public static void main(String[] args) {
     
        //通过匿名内部类创建任务类对象
        Runnable task = new Runnable() {
     
            @Override
            public void run() {
     
                for (int i = 0; i < 10; i++) {
     
                    try {
     
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
     
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        };
        //创建线程池,包涵线程数为3
        ExecutorService pool = Executors.newFixedThreadPool(3);
        //提交任务类对象给线程池中的线程对象
        //线程池自动依序分配线程并开启线程
        //如果提交线程数大于线程池线程数,线程池会依次将最先运行结束的线程对象分配给超出任务类对象
        //即超出的任务类必须等待线程池中的线程运行完毕
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
        //线程运行完毕,主线程结束,但线程池不会结束
        //用shutdown方法关闭线程池,程序才会结束
        pool.shutdown();
    }
}

线程池的好处? 为什么使用线程池?
见我的收藏 - 线程池原理

2.Callable接口

Callable(线程任务, 只能用在线程池) -> Runnable
new Thread(new Runnable(){});
new Thread(new Callable(){}); // — 错误的!!

Callable对象只能在 : Future f = pool.submit(Callable);
f.get() -> 得到call方法的返回值
可能会遇到阻塞
f.get(long, TimeUnit.xx) -> 超时继续

代码实现:

import java.util.Date;
import java.util.concurrent.*;

public class CallableDemo {
     
    public static void main(String[] args) {
     
        //创建Callable类,专门给线程池使用,无法在线程构造方法中使用
        Callable<Date> callable = new Callable<Date>() {
     
            //重写call方法,call方法有返回值,返回值类型与对象泛型相同
            @Override
            public Date call() throws Exception {
     
                for (int i = 0; i < 10; i++) {
     
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
                //延时10秒
                Thread.sleep(10000);
                //返回当前时间
                return new Date();
            }
        };
        //创建单个线程池
        ExecutorService single = Executors.newSingleThreadExecutor();
        //提交callable任务类对象,submit方法有返回值,返回值类型为future,泛型需要设置与callable返回值类型相同,未设置默认为Object
        Future<Date> f = single.submit(callable);
        /*try {
            //调用该future对象的get方法获得callable的返回值
            //因为callable的run方法中延时了10秒才返回结果,方法才结束,所以会对主方法线程产生阻塞效果
            Date date = f.get();
            //必须等待callable线程运行完成
            System.out.println(date);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }*/
        try {
     
            Date date = f.get(3, TimeUnit.SECONDS);//get方法等待三秒,如果3秒还没有返回结果,get方法结束(超时结束)
            System.out.println(date);
        } catch (InterruptedException e) {
     
            e.printStackTrace();
        } catch (ExecutionException e) {
     
            e.printStackTrace();
        } catch (TimeoutException e) {
     
            System.out.println("get方法超时");
        }
        //关闭线程池
        single.shutdown();
    }
}

2. Lambda表达式

Lambda表达式: JDK1.8 函数式编程思想
面向对象思想: 什么对象, 做什么, 结果是什么
函数式编程思想: 强调做什么,而不是以什么形式做。

语法: (参数列表) -> {一些代码}

使用Lambda前提:
1.实现一个接口
2.接口中只有一个抽象方法
3.接口对象是作为方法参数使用的

(参数列表) -> {一些代码}
(参数列表): 表示要重写的抽象方法的参数列表
-> : 固定语法, 指向/传递的意思
{一些代码}: 要重写的方法体
Lambda 取代匿名内部类的
匿名内部类: 本质还是类, 编译后也会生成字节码文件, 运行时也要加载
Lambda: 本质是一个函数, 编译后不会有字节码文件, 直接从内存中获取
效率更高
可推导即可省略:
1.() 中的参数类型, 可以省略, 如果有多个参数, 每个参数类型都要一起省略
2.{} 中如果只有一行代码, 不论这个方法有没有返回值, 那么[{} return ;] 可以省略
{} return ; 必须一起省略
3.() 中如果只有一个参数, () 可以省略, 和类型一起省略
() 中如果没有参数, 必须写 ()

代码实现:
创建函数式接口

//注解:函数式接口检测(接口中只有一个抽象方法)
@FunctionalInterface
public interface MyInterface {
     
    int echo(String s);
}

接口作为参数的Lambda表达式简化

import java.util.*;

public class LambdaDemo {
     
    //注解,属于程序的一部分,编译器可识别
    @SuppressWarnings("all")//压制全部警告
    public static void main(String[] args) {
     
        Thread thread = new Thread(new Runnable() {
     
            @Override
            public void run() {
     
                System.out.println("普通任务方法");
            }
        });
        //lambda表达式只能在参数列表里使用,且被简化的参数必须只有一个抽象方法
        //lambda表达式优化
        Thread thread1 = new Thread(() -> System.out.println("lambda表达式任务方法"));
        thread1.start();
        //创建列表
        List<String> list = List.of("lucy", "hzt", "ana", "alice");//List.of方法返回的是一个内部类,并不是真正列表
        ArrayList<String> arrayList = new ArrayList<>(list);
        Collections.sort(arrayList, new Comparator<String>() {
     
            @Override
            public int compare(String o1, String o2) {
     
                return o1.length() - o2.length();
            }
        });//传入一个比较器对象,根据长度排序
        //使用lambda简化
        Collections.sort(arrayList, ( o1,  o2) -> o1.length() - o2.length());
        System.out.println(arrayList);
        //调用将接口作为参数的方法,使用匿名内部类实现接口对象的抽象方法以创建接口对象
        method(new MyInterface() {
     
            @Override
            public int echo(String s) {
     
                return s.length();
            }
        }, "HelloWorld");
        //使用lambda进行简化
        //1.首先此方法调用了接口对象作为参数,且此接口对象只有一个必须实现的抽象方法,所以接口匿名内部类的 new 构造方法名(){} 重写方法名都可以省略
        // 用->连接(接口参数列表) -> {代码块}
        int s0 = method((String s) -> {
     return s.length();}, "HelloWorl");
        //2.调用接口的匿名内部类的参数列表中的参数类型也可以省略,多个参数的参数类型必须同时省略
        method((s) -> {
     return s.length();}, "HelloWorld");
        //3.如果调用接口的匿名内部类的参数列表中的参数只有一个,那么参数列表的()也可以省略,但是必须和列表中参数类型同时省略
        method(s -> {
     return s.length();}, "HelloWorld");
        //4.如果调用接口的匿名内部类中重写的抽象方法只有一句代码,那么 代码块的{} return ; 都可以省略且必须一起省略
        int s1 = method(s -> s.length(), "HelloWorld");//用来接收方法返回值的变量名不能与函数表达式参数相同
        System.out.println(s0 + " " + s1);
    }
    //创建一个用接口作为参数的方法
    public static int method(MyInterface inf, String s){
     
       return inf.echo(s);
    }
}

3. 注解

函数式接口: 接口中只有一个抽象方法, 默认方法\静态方法\私有方法 随意
@FunctionalInterface -> 注解
注解: JDK 1.5 属于程序的一部分, 可以取代一部分配置信息
@Override -> 检测方法是不是重写
@SuppressWarnings -> 压制警告
@Deprecated -> 标记一个类或者方法或者变量, 过时的
@FunctionalInterface -> 检测一个接口是不是函数式接口

4. 单元测试

JUnit: 单元测试 -> 以方法为单位, 可以取代主方法
System.out.println(); -> 打桩测试
Debug -> 断点测试
JUnit -> 单元测试

别人写好的代码, 我们想要使用
1.将别人写好的代码工程, 打包 jar 文件
是将编译后的字节码文件打包的
2.在自己的工程中 关联这个jar文件 -> 添加依赖
3.代码中直接使用 import

JUnit使用步骤:
1.在工程中创建一个文件夹lib
2.将2个jar包复制到lib中
3.选择jar包 右键 -> Add as Library… 默认添加即可
4.写一个测试类, 在其中写一个方法[不需要返回值,不需要参数]
5.在方法上添加注解 @Test
6.运行这个方法即可
JUnit常用注解:
@Test: 测试的方法, 可以直接运行
@Before: 在测试方法之前调用的
@After: 在测试方法之后调用的

5. 可变长参数

可变长参数:
取代了数组 int[] arr -> int… arr
JDK1.5后, 修改为可变长参数
1.方法中, 除了可变长参数, 还有别的参数, 可变长参数必须放在参数列表最后
2.而且一个方法中, 只能有一个可变长参数

代码实现:

import org.junit.Before;
import org.junit.Test;

public class tes {
     
//    @Test//单元测试方法必须是无参的
    public static void variableArity(String s, int... a){
     
        for(int i: a){
     
            System.out.println(i);
        }
        System.out.println(s);
    }
    @Before
    public void func1(){
     
        System.out.println("before注解方法在所有test注解方法之前运行");
    }
    @Test //单元测试方法可以直接运行,不需要主方法调用
    public void func2(){
     
        System.out.println("测试方法2");
    }
    @Test
    public void func3(){
     
        System.out.println("测试方法3");
    }
    @Test
    public void func4(){
     
        System.out.println("测试方法4");
    }

    public static void main(String[] args) {
     
        //可变长参数方法
        variableArity("可变长参数方法", 0);//可变长参数必须放在参数列表最后一个,且只有一个
        variableArity("可变长参数方法", 0, 1);
        variableArity("可变长参数方法", 0, 1, 2);
        variableArity("可变长参数方法", 0, 1, 2, 3);
    }
}

你可能感兴趣的:(JAVASE,java,jdk,多线程,lambda)