所需类型:
匿名内部类:可以是接口 也可以是抽象类 还可以是具体类只要重写方法就行!
Lambda表达式:只能是接口
使用限制:
如果接口中有仅只有一个抽象方法,可以使用lambda表达式,也可以使用匿名内部类
如果接口中多于一个抽象方法,只能使用匿名内部类 而不能使用lambda表达式!
实现原理:
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lamdba表达式:编译之后,没有单独的.class字节码文件,对应的字节码会在运行的时候动态生成
1.一个子类只能继承一个抽象类,但能实现多个接口
2.抽象类中可以不全是抽象方法,而接口中全是抽象方法
3.抽象类中可以有构造方法,而接口中没有
4.抽象类中可以有普通成员变量,而接口中没有
5.抽象类和接口都可以有静态成员变量,抽象类中静态成员变量访问类型任意,但接口只能public static final(默认情况);抽象类中可以有静态方法,而接口不能有
6.抽象类中的方法可以是public protected,而接口只有public
生成流:
通过数据源(集合,数组)生成流
List . steam()
中间操作:
一个流后面可以跟随零个或多个中间操作,其目的主要是为了打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个使用
Filter()
终结操作:
一个流只能有一个终结操作,当这个操作执行后,流就被使用光了,无法再被操作,所以这必定是流的最后一个操作
ForEach()
并发和并行
并行:在同一时刻,有多个任务在多个CPU上同时执行。
并发:在同一时刻,有多个任务在单个CPU上交替执行。
1 进程和线程
进程
进程简单地说就是在多任务操作系统中,每个独立执行的程序,所以进程也就是“正在进行的程序”。(Windows系统中,我们可以在任务管理器中看到进程)
线程
线程是程序运行的基本执行单元。当操作系统执行一个程序时,会在系统中建立一个进程,该进程必须至少建立一个线程(这个线程被称为主线程)作为这个程序运行的入口点。因此,在操作系统中运行的任何程序都至少有一个线程。
进程和线程
进程:就是操作系统中正在运行的一个应用程序。
线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾。
什么是多线程 ?
是指从软件或者硬件上实现多个线程并发执行的技术。
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
1 线程类概述
java.lang.Thread 是线程类,可以用来给进程创建线程处理任务使用。要使用线程先介绍两个比较重要的方法:- public void run() : 线程执行任务的方法,是线程启动后第一个执行的方法- public void start() : 启动线程的方法, 线程对象调用该方法后,Java虚拟机就会调用此线程的run方法。
2 线程的创建方式1:继承Thread方式
我们启动一个Java程序,其实默认就存在一个主线程(main方法所在线程)
接下来,我们在主线程启动一个线程,打印1到100的数字,主线程启动完线程后又打印1到100的数字。此时主线程和启动的线程在并发执行,观察控制台打印的结果。
基本步骤:
创建一个类继承Thread类。
在类中重写run方法(线程执行的任务放在这里)
创建线程对象,调用线程的start方法开启线程。
执行程序,观察控制台的打印数据的现象
线程的创建
第二种创建方式使用如下构造方法,指定任务给线程执行
public Thread(Runnable target) public Thread(Runnalbe target , String name)
参数中的Runnable是一个接口,用来定义线程要执行的任务
实现步骤如下:
定义任务类实现Runnable,并重写run方法
创建任务对象
使用含有Runnable参数的构造方法,创建线程对象并指定任务。
调用线程的start方法,开启线程。
public interface Runnable { public abstract void run();}**
线程启动后就会执行该run方法了
两种创建线程方式对比:
优点 | 缺点 | |
---|---|---|
实现Runnable | 扩展性强,实现该接口的同时还可以继承其他的类。 | 编程相对复杂,不能直接使用Thread类中的方法 |
继承Thread | 编程比较简单,可以直接使用Thread类中的方法 | 可扩展性较差, 不能再继承其他的类 |
获取和设置线程名称
获取线程的名字
String getName():返回此线程的名称
Thread类中设置线程的名字
void setName(String name):将此线程的名称更改为等于参数 name
通过构造方法也可以设置线程名称
获得当前线程的对象
public static Thread currentThread() :返回对当前正在执行的线程对象的引用
线程休眠
public static void sleep(long time):让线程休眠指定的时间,单位为毫秒。
public void join() : 具备阻塞作用 , 等待这个线程死亡,才会执行其他线程
线程的优先级
public final void setPriority(int newPriority) 设置线程的优先级
public final int getPriority() 获取线程的优先级
函数式接口有什么特点?
接口中只有一个抽象方法是需要被实现的。
函数式接口有一个特殊标志性注解,是什么?
@FunctionalInterface
接口定义
package com.itheima.Lamand;
public interface Falyble {
void fly(String s);
}
测试类实现
public static void main(_String[] args) { //匿名内部类实现 useFlayble(new Falyble() { @Override
public void fly(_String s) { _System._out.println(_s);
System._out.println(“输出了”);
} });
System._out.println(“===========”);
//Lambda表达式 useFlayble((String s)->{ _System._out.println(“有参数的lambda表达式”);
System.out.println(“直接写!”);
});
}public static void useFlayble(Falyble s){ _s.fly(“风和日丽!”);
}_
有参数Lambda表达式有参数方法!
public class Test01 { public static void main(String[] args) { useRomunHand((int a,int b)->{ return a+b; }); System.out.println(“==========”); useRom((int a,int b)->{ return a+b; }); ** } public static void useRomunHand(Randoum randoum) { int getnumber = randoum.getnumber(100,20); System.out.println(“getnumber = “ + getnumber); } public static void useRom(Randoum randoum){ int Divat = randoum.getnumber(40,40 ); System.out.println(“Divat = “ + Divat); }}@FunctionalInterfaceinterface Randoum{ int getnumber(int a,int b);}
public class StreamDemo6 { public static void main(String[] args) { ArrayList
package com.itheima.stream_demo;**import java.util.ArrayList;import java.util.Collections;import java.util.Map;import java.util.stream.Collectors;**/ Stream流的收集操作 : 第三部分* 1 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄 “zhangsan,23” “lisi,24” “wangwu,25” 2 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值 需求1 : 保留年龄大于等于24岁的人 需求2 : 并将结果收集到Map集合中,姓名为键,年龄为值 收集方法 : public static Collector toMap(Function keyMapper , Function valueMapper):把元素收集到Map集合中 */public class StreamDemo7 { public static void main(String[] args) { ArrayList
** Map
package com.itheima.stream_demo;**import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.stream.Stream;**/ Stream流中三类方法之一 : 中间方法* 1 Stream
class Student{ String name; int age;** public Student() { }** public Student(String name, int age) { this.name = name; this.age = age; }** public String getName() { return name; }** public void setName(String name) { this.name = name; }** public int getAge() { return age; }** public void setAge(int age) { this.age = age; }** @Override public String toString() { return “Student{“ + “name=’” + name + ‘\’’ + “, age=” + age + ‘}’; }}**
匿名Runnable”子类的方式实现线程
Public static void main(String[]args){
new Thread(new Runnable() { @Override public void run() {
实现的方法体! 需要定义变量写在@声明上面 } }).start();
计算器 Calculator 接口
public class Demo05 { public static void main(String[] args) { INTPL(140,110,(int a,int b)->{return a+b;}); INTPL(130, 120, (a, b) -> a - b); } public static void INTPL(int a, int b, Calculator calculator) { int result = calculator.calc(130, 120); System.out.println(“结果” + result); } interface Calculator { int calc(int a, int b); }}
Lambda表达式的基础创建!
public class LambdaDemo {
_public static void main(String[] args) {
//将集合要以降序排序
List<_Integer_> list = new ArrayList<>();
list.add(100);
list.add(300);
list.add(200);
//集合以降序排序(以前的做法:匿名对象)
// 最简化 Collections.sort(list, (o1, o2) -> o2 - o1);
Collections._sort(_list, new Comparator<_Integer_>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//集合以降序排序(新做法:Lambda表达式)
Collections._sort(_list, (Integer o1, Integer o2) -> {
return o2 - o1;
});
System._out.println(“list = “ + list);
Collections.sort(_list, (Integer o1, Integer o2) -> {
return o1 - o2;
});
System._out.println(“list = “ + list);
Collections.sort(_list, (o1, o2) -> o2 - o1);
}
}_
String 类型 使用lambda表达式 实现降序!
public class Demo04 {
_public static void main(String[] args) {
List<_String_> list = new ArrayList<>();
Collections._addAll(_list, “cab”, “bac”, “acb”, “cba”, “bca”, “abc”)_;
Collections._sort(_list, new Comparator_<_String_>() {<br /> _@Override<br /> public int compare_(_String o1, String o2_) {<br /> _return o2.compareTo_(_o1_)_;<br /> _}<br /> })_;<br /> System._out_.println_(_"list = " + list_)_;<br /> _}_<br /> 需求 :<br /> 定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10<br /> 将集合中的奇数删除,只保留偶数。<br /> 遍历集合得到2,4,6,8,10<br /> */<br />public class StreamDemo6 {<br /> public static void main(String[] args) {<br /> ArrayList<Integer> list = new ArrayList<>();<br /> for (int i = 1; i <= 10; i++) {<br /> list.add(i);<br /> }<br /> list.add(10);<br /> list.add(10);<br /> list.add(10);<br /> list.add(10);<br /> list.add(10);
// collect只负责收集流中的数据<br /> // Collectors.toList()会负责在底层创建list集合 ,并把数据添加到集合中 , 返回集合对象<br /> List<Integer> list2 = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toList());<br /> System.out.println(list2);
Set<Integer> set = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toSet());<br /> System.out.println(set);
}<br />}
day10 - Lambda,Stream,File,递归
今日目标
1 Lambda表达式
1.1 体验Lambda表达式
- ``` package com.itheima.lambda_demo;
/ Lambda表达式体验 : / public class LambdaDemo { public static void main(String[] args) { // 匿名内部类方式完成 goSwimming(new Swimming() { @Override public void swim() { System.out.println(“铁汁 , 我们去游泳吧….”); } });
// lambda表达式的方式完成
goSwimming(() -> System.out.println("铁汁 , 我们去游泳吧...."));
}
public static void goSwimming(Swimming swimming) {
swimming.swim();
}
}
interface Swimming { public abstract void swim(); }
- lambda表达式可以理解为对匿名内部类的一种简化 , 但是本质是有区别的
- 面向对象思想 :
- 强调的是用对象去完成某些功能
- 函数式编程思想 :
- 强调的是结果 , 而不是怎么去做
<a name="a739aefc"></a>
### 1.2 函数式接口
- 只有一个抽象方法需要重写的接口,函数式接口。函数式接口是允许有其他的非抽象方法的存在例如静态方法,默认方法,私有方法。
- 为了标识接口是一个函数式接口,可以在接口之上加上一个注解: [@FunctionalInterface ](/FunctionalInterface ) 以示区别
- 在JDK中 java.util.function 包中的所有接口都是函数式接口。我们之前学习线程时学习的Runnable也是函数式接口
- <br />
<a name="a7861ee2"></a>
### 1.3 Lambda表达式的使用
-
<a name="e5a85d6c"></a>
##### 使用前提
- 必须存在一个接口
- 接口中有且只有一个抽象方法
-
<a name="b2152aa4"></a>
##### 格式 : ( 形式参数 ) -> { 代码块 }
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
<a name="ceb8a348"></a>
### 1.4 Lambda表达式的案例
```java
package com.itheima.lambda_test;
/*
练习1:
1 编写一个接口(ShowHandler)
2 在该接口中存在一个抽象方法(show),该方法是无参数无返回值
3 在测试类(ShowHandlerDemo)中存在一个方法(useShowHandler)
方法的的参数是ShowHandler类型的,在方法内部调用了ShowHandler的show方法
*/
public class LambdaTest1 {
public static void main(String[] args) {
useShowHandler(() -> {
System.out.println("我是一个lambda表达式....");
});
}
public static void useShowHandler(ShowHandler showHandler) {
showHandler.show();
}
}
interface ShowHandler {
public abstract void show();
}
package com.itheima.lambda_test;
/*
1 首先存在一个接口(StringHandler)
2 在该接口中存在一个抽象方法(printMessage),该方法是有参数无返回值
3 在测试类(StringHandlerDemo)中存在一个方法(useStringHandler),
方法的的参数是StringHandler类型的,
在方法内部调用了StringHandler的printMessage方法
*/
public class LambdaTest2 {
public static void main(String[] args) {
useStringHandler((String msg) -> {
System.out.println(msg);
});
}
public static void useStringHandler(StringHandler stringHandler){
stringHandler.printMessage("今天天气不错 , 挺风和日丽的...");
}
}
@FunctionalInterface
interface StringHandler {
public abstract void printMessage(String msg);
}
package com.itheima.lambda_test;
import java.util.Random;
/*
1 首先存在一个接口(RandomNumHandler)
2 在该接口中存在一个抽象方法(getNumber),该方法是无参数但是有返回值
3 在测试类(RandomNumHandlerDemo)中存在一个方法(useRandomNumHandler),方法的的参数是RandomNumHandler类型的
在方法内部调用了RandomNumHandler的getNumber方法
*/
public class LambdaTest3 {
public static void main(String[] args) {
useRandomNumHandler(() -> {
return new Random().nextInt(10) + 1;
});
}
public static void useRandomNumHandler(RandomNumHandler randomNumHandler) {
int number = randomNumHandler.getNumber();
System.out.println(number);
}
}
interface RandomNumHandler {
public abstract int getNumber();
}
package com.itheima.lambda_test;
/*
1 首先存在一个接口(Calculator)
2 在该接口中存在一个抽象方法(calc),该方法是有参数也有返回值
3 在测试类(CalculatorDemo)中存在一个方法(useCalculator)
方法的的参数是Calculator类型的
在方法内部调用了Calculator的calc方法
*/
public class LambdaTest4 {
public static void main(String[] args) {
useCalculator((int a , int b) -> { return a + b;});
}
public static void useCalculator(Calculator calculator) {
int calc = calculator.calc(10, 20);
System.out.println(calc);
}
}
@FunctionalInterface
interface Calculator {
public abstract int calc(int a, int b);
}
2 Stream流
2.1 Stream的体验
package com.itheima.stream_demo;
import java.util.ArrayList;
/*
体验Stream流的好处
需求:按照下面的要求完成集合的创建和遍历
1 创建一个集合,存储多个字符串元素
"张无忌" , "张翠山" , "张三丰" , "谢广坤" , "赵四" , "刘能" , "小沈阳" , "张良"
2 把集合中所有以"张"开头的元素存储到一个新的集合
3 把"张"开头的集合中的长度为3的元素存储到一个新的集合
4 遍历上一步得到的集合
*/
public class StreamDemo {
public static void main(String[] args) {
// 传统方式完成
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张三丰");
list.add("谢广坤");
list.add("赵四");
list.add("刘能");
list.add("小沈阳");
list.add("张良");
// 把集合中所有以"张"开头的元素存储到一个新的集合
ArrayList<String> list2 = new ArrayList<>();
for (String s : list) {
if (s.startsWith("张")) {
list2.add(s);
}
}
// 把"张"开头的集合中的长度为3的元素存储到一个新的集合
ArrayList<String> list3 = new ArrayList<>();
for (String s : list2) {
if (s.length() == 3) {
list3.add(s);
}
}
// 遍历list3集合
for (String s : list3) {
System.out.println(s);
}
System.out.println("================================");
// Stream流的方式
list.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(s -> System.out.println(s));
}
}
2.2 Stream流的三类方法
- 获取Stream流
- 创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法
- 流水线上的操作。
- 一次操作完毕之后,还可以继续进行其他操作
- 终结方法
- 一个Stream流只能有一个终结方法
- 是流水线上的最后一个操作
2.3 第一类 : 获取方法
package com.itheima.stream_demo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
/*
Stream流中三类方法之一 : 获取方法
1 单列集合
可以使用Collection接口中的默认方法stream()生成流
default Stream<E> stream()
2 双列集合
双列集合不能直接获取 , 需要间接的生成流
可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
3 数组
Arrays中的静态方法stream生成流
*/
public class StreamDemo2 {
public static void main(String[] args) {
// 单列集合的获取
// method1();
// 双列集合的获取
// method2();
// 数组获取
// method3();
}
private static void method3() {
int[] arr = {1, 2, 3, 4, 5, 6};
Arrays.stream(arr).forEach(s -> System.out.println(s));
}
private static void method2() {
HashMap<String, String> hm = new HashMap<>();
hm.put("it001", "曹植");
hm.put("it002", "曹丕");
hm.put("it003", "曹熊");
hm.put("it004", "曹冲");
hm.put("it005", "曹昂");
// 获取map集合的健集合 , 在进行输出打印
hm.keySet().stream().forEach(s -> System.out.println(s));
// 获取map集合的entry对象 , 在输出打印
hm.entrySet().stream().forEach(s -> System.out.println(s));
}
private static void method1() {
// 可以使用Collection接口中的默认方法stream()生成流
ArrayList<String> list = new ArrayList<>();
list.add("迪丽热巴");
list.add("古力娜扎");
list.add("马尔扎哈");
list.add("欧阳娜娜");
list.stream().forEach(s -> System.out.println(s));
}
}
2.4 第二类 : 中间方法
package com.itheima.stream_demo;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.stream.Stream;
/*
Stream流中三类方法之一 : 中间方法
1 Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
Predicate接口中的方法 : boolean test(T t):对给定的参数进行判断,返回一个布尔值
2 Stream<T> limit(long maxSize):截取指定参数个数的数据
3 Stream<T> skip(long n):跳过指定参数个数的数据
4 static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
5 Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
6 Stream<T> sorted () : 将流中元素按照自然排序的规则排序
7 Stream<T> sorted (Comparator<? super T> comparator) : 将流中元素按照自定义比较器规则排序
*/
public class StreamDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张三丰");
list.add("谢广坤");
list.add("赵四");
list.add("刘能");
list.add("小沈阳");
list.add("张良");
list.add("张良");
list.add("张良");
list.add("张良");
// Stream<T> limit(long maxSize):截取指定参数个数的数据
// list.stream().limit(3).forEach(s -> System.out.println(s));
// Stream<T> skip(long n):跳过指定参数个数的数据
// list.stream().skip(3).forEach(s-> System.out.println(s));
// Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
// list.stream().distinct().forEach(s->{System.out.println(s);});
}
// // Stream<T> sorted (Comparator<? super T> comparator) : 将流中元素按照自定义比较器规则排序
private static void method3(ArrayList<String> list) {
list.stream().sorted(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}).forEach(s->{
System.out.println(s);
});
}
// Stream<T> sorted () : 将流中元素按照自然排序的规则排序
private static void method3() {
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(1);
list2.add(2);
list2.stream().sorted().forEach(s->{
System.out.println(s);
});
}
// // static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
private static void method2(ArrayList<String> list) {
ArrayList<String> list2 = new ArrayList<>();
list2.add("迪丽热巴");
list2.add("古力娜扎");
list2.add("欧阳娜娜");
list2.add("马尔扎哈");
Stream.concat(list.stream(), list2.stream()).forEach(s -> {
System.out.println(s);
});
}
// Stream<T> filter(Predicate predicate):用于对流中的数据进行过滤
private static void method1(ArrayList<String> list) {
// filter方法会获取流中的每一个数据
// s就代表的是流中的每一个数据
// 如果返回值为true , 那么代表的是数据留下来
// 如果返回值的是false , 那么代表的是数据过滤掉
// list.stream().filter(new Predicate<String>() {
// @Override
// public boolean test(String s) {
// boolean result = s.startsWith("张");
// return result;
// }
// }).forEach(s -> System.out.println(s));
list.stream().filter(s ->
s.startsWith("张")
).forEach(s -> System.out.println(s));
}
}
2.5 第三类 : 终结方法
package com.itheima.stream_demo;
import java.util.ArrayList;
import java.util.function.Consumer;
/*
Stream流中三类方法之一 : 终结方法
1 void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
2 long count():返回此流中的元素数
*/
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("张翠山");
list.add("张三丰");
list.add("谢广坤");
// long count():返回此流中的元素数
long count = list.stream().count();
System.out.println(count);
}
// void forEach(Consumer action):对此流的每个元素执行操作
private static void method1(ArrayList<String> list) {
// 把list集合中的元素放在stream流中
// forEach方法会循环遍历流中的数据
// 并循环调用accept方法 , 把数据传给s
// 所以s就代表的是流中的每一个数据
// 我们只要在accept方法中对数据做业务逻辑处理即可
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
System.out.println("=====================");
list.stream().forEach( (String s) -> {
System.out.println(s);
});
System.out.println("=====================");
list.stream().forEach( s -> { System.out.println(s); });
}
}
2.6 Stream流中的收集方法
package com.itheima.stream_demo;
import java.util.ArrayList;
/*
Stream流的收集操作 : 第一部分
需求:过滤元素并遍历集合
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
将集合中的奇数删除,只保留偶数。
遍历集合得到2,4,6,8,10
结论:在Stream流中无法直接修改集合,数组等数据源中的数据。
*/
public class StreamDemo5 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
list.stream().filter(num -> num % 2 == 0).forEach(num -> System.out.println(num));
System.out.println("=============");
// 结论:在Stream流中无法直接修改集合,数组中的数据。
System.out.println(list);
}
}
package com.itheima.stream_demo;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/*
Stream流的收集操作 : 第二部分
使用Stream流的方式操作完毕之后,我想把流中的数据起来,该怎么办呢?
Stream流的收集方法
R collect(Collector collector) : 此方法只负责收集流中的数据 , 创建集合添加数据动作需要依赖于参数
工具类Collectors提供了具体的收集方式
public static <T> Collector toList():把元素收集到List集合中
public static <T> Collector toSet():把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
需求 :
定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
将集合中的奇数删除,只保留偶数。
遍历集合得到2,4,6,8,10
*/
public class StreamDemo6 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
list.add(10);
list.add(10);
list.add(10);
list.add(10);
list.add(10);
// collect只负责收集流中的数据
// Collectors.toList()会负责在底层创建list集合 ,并把数据添加到集合中 , 返回集合对象
List<Integer> list2 = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toList());
System.out.println(list2);
Set<Integer> set = list.stream().filter(num -> num % 2 == 0 ).collect(Collectors.toSet());
System.out.println(set);
}
}
package com.itheima.stream_demo;
import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;
/*
Stream流的收集操作 : 第三部分
1 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
"zhangsan,23"
"lisi,24"
"wangwu,25"
2 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
收集方法 :
public static Collector toMap(Function keyMapper , Function valueMapper):把元素收集到Map集合中
*/
public class StreamDemo7 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");
// collect 只负责收集数据
// Collectors.toMap负责在底层创建集合对象 , 添加元素
// toMap方法中的s就是代表的是集合中的每一个元素
// 第一个参数 : 如何获取map集合中的键
// 第二个参数 : 如何获取map集合中的值
Map<String, String> map = list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) > 23).collect(
Collectors.toMap(
(String s) -> {
return s.split(",")[0];
}
,
(String s) -> {
return s.split(",")[1];
}
)
);
System.out.println(map);
}
}
3 File类
3.1 File类的介绍
- java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作
3.2 构造方法
package com.itheima.file_demo;
import java.io.File;
/*
File:它是文件和目录路径名的抽象表示
文件和目录可以通过File封装成对象
File封装的对象仅仅是一个路径名。它可以是存在的,也可以是不存在的。
构造方法 :
1 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
2 File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
3 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
*/
public class FileDemo1 {
public static void main(String[] args) {
// 1 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File f1 = new File("D:\\abc.txt");
System.out.println(f1);
// 2 File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例
File f2 = new File("D:\\aaa", "bbb.txt");
System.out.println(f2);
// 3 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例
File f3 = new File(new File("D:\\aaa"), "bbb.txt");
System.out.println(f3);
}
}
3.3 File类的创建功能
package com.itheima.file_demo;
import java.io.File;
import java.io.IOException;
/*
File类的创建功能 :
1 public boolean createNewFile() : 创建一个新的空的文件
2 public boolean mkdir() : 创建一个单级文件夹
3 public boolean mkdirs() : 创建一个多级文件夹
*/
public class FileDemo2 {
public static void main(String[] args) throws IOException {
File f1 = new File("D:\\a.txt");
// 1 public boolean createNewFile() : 创建一个新的空的文件
System.out.println(f1.createNewFile());
File f2 = new File("day10_demo\\aaa");
// 2 public boolean mkdir() : 创建一个单级文件夹
System.out.println(f2.mkdir());
File f3 = new File("day10_demo\\bbb\\ccc");
// 3 public boolean mkdirs() : 创建一个多级文件夹
System.out.println(f3.mkdirs());
}
}
3.4 File类的删除功能
package com.itheima.file_demo;
import java.io.File;
import java.io.IOException;
/*
File类删除功能 :
public boolean delete() 删除由此抽象路径名表示的文件或目录
注意 :
1 delete方法直接删除不走回收站。
2 如果删除的是一个文件,直接删除。
3 如果删除的是一个文件夹,需要先删除文件夹中的内容,最后才能删除文件夹
*/
public class FileDemo3 {
public static void main(String[] args) throws IOException {
File f1 = new File("D:\\a.txt");
// 1 public boolean createNewFile() : 创建一个新的空的文件
System.out.println(f1.delete());
File f2 = new File("day10_demo\\aaa");
// 2 public boolean mkdir() : 创建一个单级文件夹
System.out.println(f2.delete());
File f3 = new File("day10_demo\\bbb");
// 3 public boolean mkdirs() : 创建一个多级文件夹
System.out.println(f3.delete());
}
}
3.5 File类的判断和获取功能
package com.itheima.file_demo;
import java.io.File;
/*
File类判断和获取功能
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件或目录的名称
*/
public class FileDemo4 {
public static void main(String[] args) {
File f1 = new File("day10_demo\\aaa");
File f2 = new File("day10_demo\\a.txt");
// public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
System.out.println(f1.isDirectory());
System.out.println(f2.isDirectory());
// public boolean isFile() 测试此抽象路径名表示的File是否为文件
System.out.println(f1.isFile());
System.out.println(f2.isFile());
// public boolean exists() 测试此抽象路径名表示的File是否存在
System.out.println(f1.exists());
// public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
System.out.println(f1.getAbsolutePath());
// public String getPath() 将此抽象路径名转换为路径名字符串
System.out.println(f1.getPath());
// public String getName() 返回由此抽象路径名表示的文件或目录的名称
System.out.println(f2.getName());
}
}
3.6 File类高级获取功能
package com.itheima.file_demo;
import java.io.File;
/*
File类高级获取功能
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组
listFiles方法注意事项:
1 当调用者不存在时,返回null
2 当调用者是一个文件时,返回null
3 当调用者是一个空文件夹时,返回一个长度为0的数组
4 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
5 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
*/
public class FileDemo5 {
public static void main(String[] args) {
File file = new File("day10_demo\\bbb\\ccc");
// 返回此抽象路径名表示的目录中的文件和目录的File对象数组
File[] files = file.listFiles();
// 遍历File类的数组
for (File f : files) {
// 拿到每一个文件的文字
System.out.println(f.getName());
}
}
}
练习 :
package com.itheima.file_demo;
import java.io.File;
import java.util.HashMap;
/*
练习二 :统计一个文件夹中每种文件的个数并打印。
打印格式如下:
txt:3个
doc:4个
jpg:6个
…
*/
public class FileTest2 {
public static void main(String[] args) {
File file = new File("day10_demo\\统计文件个数文件夹");
getFileCount(file);
}
public static void getFileCount(File f) {
HashMap<String, Integer> hm = new HashMap<>();
// 是文件夹在获取所有的子文件
if (f.isDirectory()) {
File[] files = f.listFiles();
// 遍历数组
for (File file : files) {
String fileName = file.getName();
String name = fileName.split("\\.")[1];
if (hm.containsKey(name)) {
hm.put(name, hm.get(name));
} else {
hm.put(name, 1);
}
}
}
System.out.println(hm);
}
}
4 递归
-
概述
- 递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象
-
好处
- 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
小的问题解决 , 大的问题也会逐一进行解决
- 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
-
注意
- 递归出口:否则会出现内存溢出
- 递归规则:需要找到与原问题相似的规模较小的问题
-
案例
- ``` package com.itheima.recursion_demo;
/* 需求:用递归求5的阶乘,并把结果在控制台输出
思路:
1 定义一个方法,用于递归求阶乘,参数为一个int类型的变量
2 在方法内部判断该变量的值是否是1
是:返回1
不是:返回n*(n-1)!
3 调用方法
4 输出结果
*/ public class Demo1 { public static void main(String[] args) { int result = jc(5); System.out.println(“5的阶乘是:” + result); }
private static int jc(int n) {
if (n == 1) {
return 1;
}
return n * jc(n - 1);
}
}
-
package com.itheima.recursion_demo;
import java.io.File;
/* 需求 : 使用递归删除计算机中指定的文件夹
删除D盘中的aaa文件夹!
*/ public class Demo2 { public static void main(String[] args) { File f = new File(“D:\aaa”); deleteFiles(f); }
private static void deleteFiles(File f) {
File[] files = f.listFiles();
for (File file : files) {
if (file.isDirectory()) {
// 递归
deleteFiles(file);
} else {
// 删除文件
file.delete();
}
}
// 删除当前文件夹
f.delete();
}
}
<a name="4e99e578"></a>
# day08-异常,多线程
<a name="26537096"></a>
## 今日目标 :
- 异常的概述
- 异常的分类
- 异常的处理方式
- 自定义异常
- 多线程入门
<a name="58c65ffb"></a>
## 1 异常的概述
<a name="2131ec86"></a>
### 1.1 什么是异常?
- 异常就是程序出现了不正常情况 , 程序在执行过程中 , 数据导致程序不正常 , 最终导致了JVM的非正常停止
- 注意 : 语句错误不算在异常体系中
<a name="9347c077"></a>
### 1.2 异常的存在的形式
- 异常有类型之分,比如我们之前有接触过的比较熟悉的数组越界异常(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException),类型转换异常(ClassCastException)。当程序中产生异常时,其实就是在异常的位置创建了一个该异常的对象,该对象携带了相关的异常信息。
- 简单来说 : 异常就是Java中提供的类的对象
<a name="ea3f79f9"></a>
### 1.3 程序中异常产生后,是如何处理的
- 程序中一旦产生异常,首先会中断向下执行。异常的传递要根据处理方式(后面章节会讲到)而定,如果没有处理,默认是将异常传递给本方法的调用者。不断往回传递,直到JVM收到该异常,此时程序终止执行
<a name="d395cb7b"></a>
## 2 异常的分类
- 编译时期异常
- 非RuntimeException及其子类 : 编译时异常就是在编译的时候可能出现的异常, 编译时期必须处理,否则程序无法执行
- 运行时期异常
- RuntimeException及其子类 : 运行时异常就是在运行时可能出现的异常, 在编译时期不需要处理
<a name="9f5112ff"></a>
## 3 异常的处理方式
<a name="a98f7810"></a>
### 3.1 JVM处理异常的方式
- 如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理 , 那么JVM是如何处理的呢 ?
- 把异常的类型 , 原因 , 位置打印在控制台
- 程序停止执行
- 注意 : 程序中出现了异常 , 会在当前位置创建此异常的对象 , 对象中包含了异常的信息 , 并把此异常交给本方法的调用者处理
- 缺点 : 用户体验不好
<a name="299e39b6"></a>
### 3.2 手动处理异常方式
<a name="a4bddcbb"></a>
#### 3.2.1 声明异常
- 声明异常—— throws
- 修饰符 返回值类型 方法名(参数列表) throws 异常类型1 , 异常的类型2... { ... }
- 举例 : public void show() throws NullPointerException , ArrayIndexOutOfBoundsException { .... }
- 作用 :
- 表示调用当前的方法可能会出现某些异常,使用时需要注意哦!
- 如果当前方法没有出现任何异常, 那么代码会正常执行
- 如果当前方法中出现了异常 , 会把异常交给本方法调用者处理(甩锅)
-
```java
package com.itheima.exception_demo;
import sun.java2d.pipe.SpanShapeRenderer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
声明异常—— throws
格式 : 修饰符 返回值类型 方法名(参数列表) throws 异常类型1 , 异常的类型2... { ... }
举例 : public void show() throws NullPointerException , ArrayIndexOutOfBoundsException { .... }
作用 :
1 表示告知调用者当前的方法可能会出现某些异常,使用时需要注意哦!
2 如果当前方法没有出现任何异常, 那么代码会正常执行
3 如果当前方法中出现了异常 , 会把异常交给本方法调用者处理(甩锅)
需求 :
练习 : 定义两个方法一个运行时期异常 , 一个声明编译时期异常 !
注意 :
1 编译时异常因为在编译时就会检查,所以必须要写在方法后面进行显示声明
2 运行时异常因为在运行时才会发生,所以在方法后面可以不写
3 如果声明多个异常有子父类关系 , 那么只要声明一个父类即可(多态)
*/
public class Exception_Throws {
public static void main(String[] args) throws ParseException{
printArr();// 如果此方法出现了异常 , 会交给jvm进行处理
StringToDate();// 如果此方法出现了异常 , 会交给jvm进行处理
}
// 1 告诉调用者 , 此方法可能会出现异常哦
// 2 如果此方法没有出现异常 , 那么会正常执行
// 3 如果此方法中出现了异常 , 会把此异常交给调用者处理
// 注意 : 如果声明的异常是一个运行时期异常 , 那么此声明可以省略
public static void printArr() /*throws NullPointerException*/ {
int[] arr = null;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
// 1 告诉调用者 , 此方法可能会出现异常哦
// 2 如果此方法没有出现异常 , 那么会正常执行
// 3 如果此方法中出现了异常 , 会把此异常交给调用者处理
// 注意 : 如果声明的异常 是一个编译时期异常 , 那么在编译时期必须处理 , 要么程序无法执行
public static void StringToDate() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2000-03-11 12:12:12");
}
}
3.2.2 抛出异常
-
思考:
- 以前出现了异常,虚拟机帮我们创建一个异常对象,抛给调用者。但是如果我们需要自己手动创建一个异常对象该如何写?
-
格式 :
修饰符 返回值类型 方法名(参数列表) {
throw new 异常对象();
}
-
注意 :
- 抛出异常的格式必须在方法的内部完成
- 如果手动抛出一个异常,下面的代码无法执行
- ```java package com.itheima.exception_demo;
/* 抛出异常演示 : 格式 : 修饰符 返回值类型 方法名(参数列表) { throw new 异常对象(); }
注意 :
1 抛出异常的格式必须在方法的内部完成
2 如果手动抛出一个异常,下面的代码无法执行
*/ public class Exception_Throw { public static void main(String[] args) { System.out.println(“家里有一个貌美如花的老婆”); System.out.println(“还有一个当官的兄弟”); System.out.println(“自己还有一个买卖”); System.out.println(“这样的生活你要不要?”);
// 程序不想往下执行了 ,怎么做 ???
// 1 自己手动制造出一个异常
// 2 当前异常也是交给了方法的调用者处理 , 也就是jvm处理
// 3 下面代码无法执行
throw new RuntimeException();
// System.out.println("武大郎的标准生活!");
}
}
-
<a name="02c501bb"></a>
##### 作用 :
- 在方法中,当传递的参数有误,没有继续运行下去的意义了,则采取抛出处理,表示让该方法结束运行。
- 告诉调用者方法中出现的问题原因
```java
package com.itheima.exception_demo;
/*
抛出异常存在的意义所在 :
1 在方法中,当传递的参数有误,没有继续运行下去的意义了,则采取抛出处理,表示让该方法结束运行。
2 告诉调用者方法中出现了问题
练习 : 定义一个方法 , 方法的参数接收一个数组 , 在方法中遍历数组 .
需求1 : 如果方法接收的数组为null , 使用输出语句提示
需求2 : 如果方法接收的数组为null , 使用抛出异常解决
思考 : 两种方式的区别在哪里 ?
*/
public class Exception_Throw2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
arr = null;
// printArr1(arr);
printArr2(arr);// 接收方法返回的异常 , 但是此异常有jvm进行处理
}
// 需求1 : 如果方法接收的数组为null , 使用输出语句提示
public static void printArr1(int[] arr) {
if (arr == null) {
System.out.println("数组为null");
} else {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
// 需求2 : 如果方法接收的数组为null , 使用抛出异常解决
public static void printArr2(int[] arr) {
if (arr == null) {
throw new RuntimeException();
} else {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
}
3.2.3 throws和throw的区别
- throws :
- 用在方法声明后面,跟的是异常类名
- 表示声明异常,告知调用者调用该方法有可能会出现这样的异常
- throw :
- 用在方法体内,跟的是异常对象名
- 表示手动抛出异常对象,告知调用者数据传入有误
3.2.4 捕获异常
- 捕获处理异常介绍 : try, catch
- 之前的声明或者抛出都是将异常传递出去,让调用者知道异常信息。
而捕获处理是本方法内部进行处理 , 能够阻止异常的传递,从而保证程序能够继续往下执行。
- 之前的声明或者抛出都是将异常传递出去,让调用者知道异常信息。
捕获异常的格式
try {
try中存放可能会出现问题的代码
1.代码...
2.代码...
3.代码...
} catch (异常类型 变量名) {
4.处理异常方案
打印异常,获取异常原因记录日志......)
}
5.其他代码...
执行方式
- 如果 try 中没有遇到问题,怎么执行?
- 从上往下依次执行 , catch中不执行
- 如果 try 中代码2遇到了问题,问题下面的代码还会执行吗?
- 不会执行,会拿当前异常对象和异常类型匹配,匹配成功执行处理异常代码
- 如果出现的问题没有被捕获,那么程序如何运行?
- 如果异常没有捕获到 , 虚拟机会帮助我们处理
- 如果 try 中没有遇到问题,怎么执行?
- 多异常捕获处理方案
- 多个异常,每个异常单独处理
- ```java try{ 异常1 }catch(异常1){
- 多个异常,每个异常单独处理
} try{ 异常2 }catch(异常2){
}
- 多个异常,一次捕获,多次处理
-
```java
try{
异常1
异常2
}catch(异常1){
}catch(异常2){
}
- 多个异常,异常一次捕获,一次处理
try{
异常1
异常2
}catch(Exception e){
}
3.3 Throwable 的成员方法
方法名 | 说明 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
3.4 异常练习
package com.itheima.exception_demo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
/*
定义一个方法接收一个生日日期字符串(xxxx年xx月xx)
main方法中让用户输入一个生日日期字符串,调用设计好的方法计算在地球上活了多少天。
要求:如果解析发生异常,捕获异常,提示用户要重新输入生日日期字符串,直到输入正确的日期为止。
思考:设计代此码的过程中想想什么时候捕获异常,什么时候声明异常?
*/
public class ExceptionTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入生日(xxxx-xx-xx):");
while (true) {
String birthday = sc.nextLine();
try {
method(birthday);
break;// 如果生日没有问题结束死循环
} catch (ParseException e) {
System.out.println("录入生日格式有误!");
}
}
}
public static void method(String strDate) throws ParseException {
// 创建日期模板对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 解析字符串
Date date = sdf.parse(strDate);
// 获取生日到1970/1/1 经历的毫秒值
long time1 = date.getTime();
// 当前系统时间到1970/1/1 经历的毫秒值
Date d2 = new Date();
long time2 = d2.getTime();
System.out.println("活了" + (time2 - time1) / (1000L * 60 * 60 * 24) + "天");
}
}
4 自定义异常
4.1 概述
- 当JDK中的异常类型,不满足实际的业务需要时。就可以自己定义异常。例如,学生的年龄数据,如果是负数或者数据 超过了150认为是不合法的,就需要抛出异常。JDK中就没有表示年龄的异常,就需要自己定义异常了
4.2 实现步骤
- 定义异常类
- 写继承关系
- 空参构造
- 带参构造
4.3 自定义异常注意
- 如果要自定义编译时异常,就继承Exception
- 如果要自定义运行时异常,就继承RuntimeException
5 多线程入门
5.1 多线程相关的概念
- 并发与并行
- 并行:在同一时刻,有多个任务在多个CPU上同时执行。
- 并发:在同一时刻,有多个任务在单个CPU上交替执行。
- 进程与线程
- 进程:就是操作系统中正在运行的一个应用程序。
- 线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾。
5.2 什么是多线程
- 是指从软件或者硬件上实现多个线程并发执行的技术。
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。 - 好处 : 提高任务的执行性能
5.3 多线程的创建方式
5.3.1 继承Thread方式
- 基本步骤:
- 创建一个类继承Thread类。
- 在类中重写run方法(线程执行的任务放在这里)
- 创建线程对象,调用线程的start方法开启线程。
- 执行程序,观察控制台的打印数据的现象 ```java package com.itheima.thread_demo;
/* 线程的创建方式1:继承Thread方式
基本步骤 :
1 创建一个类继承Thread类。
2 在类中重写run方法(线程执行的任务放在这里)
3 创建线程对象,调用线程的start方法开启线程。
需求 :
我们启动一个Java程序,其实默认就存在一个主线程(main方法所在线程)
接下来,我们在主线程启动一个线程,打印1到100的数字,主线程启动完线程后又打印1到100的数字。
此时主线程和启动的线程在并发执行,观察控制台打印的结果。
*/ public class MyThread01 { public static void main(String[] args) { // 创建线程对象,调用线程的start方法开启线程。 MyThread mt = new MyThread(); mt.start();
// main方法中的任务
for (int i = 1; i <= 100; i++) {
System.out.println("i:" + i);
}
}
} // 创建一个类继承Thread类。 class MyThread extends Thread { // 在类中重写run方法(线程执行的任务放在这里) @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println(“i:” + i); } } }
<a name="7e24284a"></a>
#### 5.3.2 实现Runable方式
- 构造方法
- public Thread(Runnable target)
- public Thread(Runnalbe target , String name)
- 实现步骤
- 定义任务类实现Runnable,并重写run方法
- 创建任务对象
- 使用含有Runnable参数的构造方法,创建线程对象并指定任务。
- 调用线程的start方法,开启线程
```java
package com.itheima.thread_demo;
/*
线程的创建方式2:实现Runnable方式
基本步骤 :
1 定义任务类实现Runnable,并重写run方法
2 创建任务对象
3 使用含有Runnable参数的构造方法,创建线程对象并指定任务。
4 调用线程的start方法,开启线程
需求 :
我们启动一个Java程序,其实默认就存在一个主线程(main方法所在线程)
接下来,我们在主线程启动一个线程,打印1到100的数字,主线程启动完线程后又打印1到100的数字。
此时主线程和启动的线程在并发执行,观察控制台打印的结果。
*/
public class MyThread02 {
public static void main(String[] args) {
// 创建线程对象,调用线程的start方法开启线程。
MyRunnable mr = new MyRunnable();
Thread thread= new Thread(mr);
thread.start();
// main方法中的任务
for (int i = 1; i <= 100; i++) {
System.out.println("i:" + i);
}
}
}
// 1 定义任务类实现Runnable,并重写run方法
class MyRunnable implements Runnable {
// 在类中重写run方法(线程执行的任务放在这里)
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println("i:" + i);
}
}
}
5.3.3 Thread类中常用方法
- String getName():返回此线程的名称
- Thread类中设置线程的名字
- void setName(String name):将此线程的名称更改为等于参数 name
- 通过构造方法也可以设置线程名称
- public static Thread currentThread():返回对当前正在执行的线程对象的引用
- public static void sleep(long time):让线程休眠指定的时间,单位为毫秒
- 线程有两种调度模型
- 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程 - 获取的 CPU 时间片相对多一些 ```java package com.itheima.thread_demo.thread_method;
- 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
/* 线程有两种调度模型 1 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片 2 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程 获取的 CPU 时间片相对多一些
注意 : Java使用的是抢占式调度模型
优先级高 , 只是抢夺到cpu执行的概率高而已 , 只是一种概率问题
*/ public class PriorityDemo { public static void main(String[] args) { Thread thread1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + “:” + i); } } }); // 优先级最低 thread1.setPriority(1); thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
});
// 优先级最高
thread2.setPriority(10);
thread2.start();
}
} ```
package com.itheima.thread_demo.thread_method;
/*
线程有两种调度模型
1 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
2 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程
获取的 CPU 时间片相对多一些
注意 : Java使用的是抢占式调度模型
优先级高 , 只是抢夺到cpu执行的概率高而已 , 只是一种概率问题<br /> */<br />public class PriorityDemo {<br /> public static void main(String[] args) {<br /> Thread thread1 = new Thread(new Runnable() {<br /> @Override<br /> public void run() {<br /> for (int i = 0; i < 1000; i++) {<br /> System.out.println(Thread.currentThread().getName() + ":" + i);<br /> }<br /> }<br /> });<br /> // 优先级最低<br /> thread1.setPriority(1);<br /> thread1.start();
Thread thread2 = new Thread(new Runnable() {<br /> @Override<br /> public void run() {<br /> for (int i = 0; i < 1000; i++) {<br /> System.out.println(Thread.currentThread().getName() + ":" + i);<br /> }<br /> }<br /> });<br /> // 优先级最高<br /> thread2.setPriority(10);<br /> thread2.start();<br /> }