Java基础学习
- 一、不可变集合
- 二、Stream流
- 2.1 Stream流数据添加
- 2.2 Stream流的中间方法
- 2.3 Stream终结方法
- 三、 方法引用
- 3.1 方法引用的基本概念
- 3.2 方法引用的分类
- 3.2.1 引用静态方法
- 3.2.2 引用成员方法
- 3.2.3 引用构造方法
- 3.2.4 使用类名引用成员方法
- 3.2.5 引用数组的构造方法
- 四、异常
- 4.1 异常
- 4.1.1 运行时异常和编译时异常的区别
- 4.1.2 异常的作用
- 4.2 异常处理方式
- 4.2.1 JVM默认的处理方式
- 4.2.2 自己处理
- 常见问题
- 4.3 Throwable 的成员方法
- 4.4 抛出异常
- 代码实现
- 4.5 自定义异常
一、不可变集合
不可变集合
:就是不可以改变集合内容,长度
运用场景:
- 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践 或者当集合对象被不可信的库调用时,不可变形式是安全的
- 简单理解:不想让别人修改集合中的内容
书写格式:
- 在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合。
主要方法
方法名称 | 说明 |
---|---|
static List of(E…elements) | 创建一个具有指定元素的List集合对象 |
static Set of(E…elements) | 创建一个具有指定元素的Set集合对象 |
static <K .V> Map<K,V> of(E…elements) | 创建一个具有指定元素的Map集合对象 |
注意:
List直接使用
Set: 元素不能重复
Map: 元素不能重复、键值对数量最多是10个 超过10个用ofEntries方法
二、Stream流
Stream流的使用步骤:
- 先得到一条Stream流(流水线),并把数据放上去
- 使用中间方法对流水线上的数据进行操作
- 使用终结方法对流水线上的数据进行操作
2.1 Stream流数据添加
package Stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.stream.Stream;
public class StreamCreat {
public static void main(String[] args) {
//创建一个单列集合的Stream流
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,2,3,5,4);
list.stream().forEach(s-> System.out.println(s));
//创建一个双列的集合
HashMap<String,Integer> hm = new HashMap<>();
hm.put("黄埔",111);
hm.put("们都",222);
hm.put("阿松大",333);
hm.put("o",444);
hm.keySet().stream().forEach(s-> System.out.println(s));
//创建一个数组
String[] arr = {"as","asd","asdasdas","xzca","wad"};
Arrays.stream(arr).forEach(s-> System.out.println(s));
//零散的数据
Stream.of(1,2,3,4).forEach(s-> System.out.println(s));
}
}
注意:
- stream接口中静态方法of的细节
- 方法的形参是一个可变参数,可以传递一堆
零散的数据
,也可以传递数组但是数组必须是引用数据类型的
- 如果
传递基本数据类型
,是会把整个数组当做一个元素
,放到Stream当中。
,其返回的就是一个地址值了
2.2 Stream流的中间方法
注意:
中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式
修改Stream流中的数据,不会影响原来集合或者数组中的数据
package Stream;
import java.util.ArrayList;
import java.util.Collections;
public class StreamContent {
public static void main(String[] args) {
//创建方法,并且添加数据
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张阿松大-22","黄阿松-11","西欧我-33","黄阿萨-87","阿萨松-33","阿萨松-12","阿萨松-32","阿萨松-32");
//过滤方法
list1
.stream()
.filter(s->s.startsWith("黄"))
.forEach(s-> System.out.println(s));
//获取前面几个数据
list1.stream().limit(3).forEach(s-> System.out.println(s));
//跳过前面几个数据
list1.stream().skip(3).forEach(s-> System.out.println(s));
//集合去重
list1.stream().distinct().forEach(s-> System.out.println(s));
//合并a,b,两个集合
// Stream.concat(list1,list1);
//转化流的数据类型
list1.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));
}
}
2.3 Stream终结方法
package Stream;
import java.util.*;
import java.util.stream.Collectors;
public class StreamCollect {
public static void main(String[] args) {
//创建Arraylist集合
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-女-18","张强-男-87","张三丰-男-21","张翠山-女-18","张良-男-18","王二麻子-女-15","谢广坤-女-18");
//用Arraylist接收
List<String> collect = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toList());
System.out.println(collect);
//用Set接收(里面不能有重复的元素)
Set<String> Set = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(Set);
//用map接收
Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0]
,
s -> Integer.parseInt(s.split("-")[2])
));
System.out.println(map);
}
}
IntFunction的泛型
: 具体类型的数组
apply的形参:流中数据的个数,要跟数组的长度保持一致
apply的返回值: 具体类型的数组方法体: 就是创建数组
toArray方法
的参数的作用: 负责创建一个指定类型的数组
toArray方法
的底层,会依次得到流里面的每一个数据,并把数据放到数组中
toArray方法
的返回值: 是一个装着流里面所有数据的数组
toMap:
toMap :
参数一
:表示键的生成规则参数二
:表示值的生成规则
参数一:
Function
泛型一
: 表示流中每一个数据的类型泛型二:
表示Map集合中键的数据类型 方法apply形参:依次表示流里面的每一个数据方法体:生成键的代码返回值:已经生成的键
参数二:
Function
泛型一:
表示流中每一个数据的类型泛型二
: 表示Map集合中值的数据类型 方法apply形参:依次表示流里面的每一个数据方法体:生成值的代码返回值: 已经生成的值
三、 方法引用
3.1 方法引用的基本概念
概念:把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体
方法引用
- 引用处需要是函数式接口
- 被引用的方法需要已经存在
- 被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
- 被引用方法的功能需要满足当前的要求
::是什么符号?
方法引用符
package Stream.方法引用;
import java.util.Arrays;
import java.util.Comparator;
public class funcationDom1 {
public static void main(String[] args) {
//创建一个数组,随机添加数据,最后的数据要是按降序的排列
Integer[] arr = {1,8,26,9,3,95};
//1. 通过匿名内部类的形式进行排序
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
// 2. 通过lambda的形式进行排序
Arrays.sort(arr,(o1,o2) -> o2-o1);
//3. 通过引用函数的形式来进行排列
Arrays.sort(arr,funcationDom1::subtraction);
System.out.println(Arrays.toString(arr)); //[95, 26, 9, 8, 3, 1]
}
public static int subtraction(int num1 , int num2){
return num2 - num1;
}
}
3.2 方法引用的分类
- 引用静态方法
- 引用成员方法
- 引用构造方法
- 其他调用方式
3.2.1 引用静态方法
格式:类名::静态方法
范例:
Integer::parseInt
package Stream.方法引用;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
public class Dom2 {
public static void main(String[] args) {
//创建集合,将数组当中的字符串变为int类型
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"1","2","3","4","56");
//1. 利用匿名内部类
list.stream()
.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).forEach(s-> System.out.println(s));
//2. 利用调用静态方法来实现
list.stream()
.map(Integer::parseInt).forEach(s-> System.out.println(s));
}
}
3.2.2 引用成员方法
格式:对象::成员方法()
其他类:其他类对象::方法名
本类: this::方法名
父类: super::方法名
其他类:
list.stream()
.filter(new StringOperration()::StringJudge)
.foreach(s->system.out.printIn(s));
本类:
list.stream()
.filter(this::StringJudge)
.foreach(s->system.out.printIn(s));
如果是静态方法时,没有this,我们只能用重新创建本类方法(new 本类方法名)
父类:
list.stream()
.filter(super::StringJudge)
.foreach(s->system.out.printIn(s));
3.2.3 引用构造方法
格式:类名::new
范例:
student::new
package Method_reference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
public class Dome6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三,12","李四,12","王五,12");
//原先的方法使集合里面的数据转换为对象类型的
list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
String[] split = s.split(",");
String name = split[0];
int age = Integer.parseInt(split[1]);
return new Student(name,age);
}
}).forEach(s-> System.out.println(s));
//使用引用构造方法map集合
list.stream().map(Student::new).forEach(s-> System.out.println(s));
}
}
package Method_reference;
public class Student {
private String name;
private int age;
public Student() {
}
//重写一个带一个参数的构造函数
public Student(String str){
String[] split = str.split(",");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}
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;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
3.2.4 使用类名引用成员方法
格式:类名::成员方法
范例:
String::substring
方法引用的规则:
- 需要有函数式接口
- 被引用的方法必须已经存在
- 被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
- 被引用方法的功能需要满足当前的需求
抽象方法形参的详解:
第一个参数
:表示被引用方法的调用者,决定了可以引用哪些类中的方法在stream流当中,第一个参数
一般都表示流里面的每一个数据。假设流里面的数据是字符串
,那么使用这种方式进行方法引用,只能
引用string这个类中的方法
第二个参数到最后一个参数
:跟被引用方法的形参保持一致
,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
将集合当中的所有数据全部变成大写输出
package Stream.方法引用;
import java.util.ArrayList;
import java.util.Collections;
public class Dom3 {
public static void main(String[] args) {
//创建Arraylist对象并且添加对象
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc");
//将所有的字母变成大写并且输出
//.map(String::toUpperCase) : 表示拿着stream里面的每一个数据去调用String方法里面的toUpperCase
list.stream()
.map(String::toUpperCase)
.forEach(s-> System.out.println(s));
//方法二
/* list.stream()
.map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s-> System.out.println(s));
*/
}
}
3.2.5 引用数组的构造方法
格式:数据类型I::new
范例:
int[]::new
集合中存储一些整数,收集到数组当中:
数组的类型,需要跟流中数据的类型保持一致。
package Stream.方法引用;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;
public class Dom4 {
public static void main(String[] args) {
//创建集合,添加整型数据
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5);
//将数据添加到数组当中
Integer[] array = list.stream()
.toArray(Integer[]::new);
System.out.println(Arrays.toString(array));//[1, 2, 3, 4, 5]
//法二:
Integer[] arr = list.stream()
.toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
System.out.println(Arrays.toString(arr));//[1, 2, 3, 4, 5]
}
}
四、异常
4.1 异常
异常
:异常就是代表程序出现的问题
当出现异常时,该怎么处理事情
Exception
:叫做异常,代表程序可能出现的问题我们通常会用Exception以及他的子类来封装程序出现的问题运行时异常
:RuntimeException及其子类,编译阶段不会出现异常提醒运行时出现的异常(如:数组索引越界异常编译时异常
:编译阶段就会出现异常提醒的。 (如:日期解析异常)
4.1.1 运行时异常和编译时异常的区别
编译时异常
:除了RuntimeExcpetion和他的子类,其他都是编译时异常。编译阶段需要进行处理,作用在于提醒程序员。运行时异常
: RuntimeException本身和所有子类,都是运行时异常编译阶段不报错,是程序运行时出现的。一般是由于参数传递错误带来的问题
4.1.2 异常的作用
-
作用一
: 异常是用来查询bug的关键参考信息 -
作用二
: 异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
搭建的条件
public void setAge(int age) {
if (age>40 || age<18){
throw new RuntimeException();
}else {
this.age = age;
}
}
初始:
package 异常;
public class Dom1 {
public static void main(String[] args) {
//创建对象
Student s = new Student("zhangsn",13);
s.setAge(90);
}
}
结果
4.2 异常处理方式
- JVM默认的处理方式
- 自己处理
- 抛出异常
4.2.1 JVM默认的处理方式
- 把
异常的名称
,异常原因
及异常出现的位置
等信息输出
在了控制台
程序停止执行
,下面的代码不会再执行了
代码:
package 异常;
public class Dom1 {
public static void main(String[] args) {
//创建对象
Student s = new Student("zhangsn",13);
System.out.println("我先执行一步");
s.setAge(90);
System.out.println("看看我执行没");
}
}
控制台报错,并且不会执行后面代码
4.2.2 自己处理
格式:
try {
可能出现异常的代码;
catch(异常类名 变量名){
异常的处理代码;
原理解释:
- 此处出现了异常,程序就会在这里创建一个ArrayIndexOutofBoundsException对象
- new ArrayIndexOutofBoundsException();
- 拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象如果
能被接收
,就表示该异常就被捕获(抓住),执行catch里面对应的代码
- 当catch里面所有的代码执行完毕,继续执行try…catch体系下面的其他代码
package 异常;
public class Dom2 {
public static void main(String[] args) {
//创建对象
int[] arr = {1,2,3,4,5};
System.out.println("我先执行一步");
try {
System.out.println(arr[5]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("出现错误,错误信息:"+e);
}
System.out.println("看看我执行没");
}
}
控制台:
该方法好处,就是可以执行下面的代码
常见问题
- 如果try中可能会遇到多个问题,怎么执行?
- 我们会创建多个catch来捕获其他的对象
如果再出现多个异常时,要把父类写在最后一个
因为如果父类放到最前面的话,会将其子类所有的异常都接收
package 异常;
public class Dom3 {
public static void main(String[] args) {
int[] arr = {1,2,34,5,51};
try {
System.out.println(1/0);
System.out.println(arr[5]);
String s = null;
System.out.println(s.equals("asd"));
}catch (NullPointerException e){
System.out.println("空指针异常");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界");
}catch (ArithmeticException e){
System.out.println("分母不为");
}
System.out.println("看看我执行了吗s");
}
}
执行时机是,捕捉到就跳转,不会执行try该代码下面的代码,直接去catch当中查询其捕捉到的异常,若无就会是JVM自动给你报错,导致后面的代码无法实现
4.3 Throwable 的成员方法
方法名称 | 说明 |
---|---|
public string getMessage() | 返回此 throwable 的详细消息字符串 |
public String tostring() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
快捷键生成try……catch --> ctrl + Alt + t
package 异常;
public class Dom4 {
public static void main(String[] args) {
//创建对象
int[] arr = {1,2,3,4,5};
System.out.println("我先执行一步");
try {
System.out.println(arr[5]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e.getMessage());//Index 5 out of bounds for length 5
System.out.println(e.toString());//java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
e.printStackTrace();//打印红色报错,包含上面两个信息+出错位置。他还不会影响到后面代码的实现
}
System.out.println("看看我执行没");
}
}
4.4 抛出异常
代码实现
GirlFrend代码细节地方:
public void setName(String name) {
int len = name.length();
if (len<3 || len>10){
throw new RuntimeException();//运行时错误
}
this.name = name;
}
public void setAge(int age) {
if (age>40 || age<18){
throw new RuntimeException();
}
this.age = age;
}
main代码:
package 异常;
import java.util.Scanner;
public class Exercise {
public static void main(String[] args) {
//键盘录入女朋友名字(长度3-10)和年龄(18-40)
Scanner sc = new Scanner(System.in);
GirlFriend gf = new GirlFriend();
while (true) {
try {
System.out.println("请输入你女朋友的名字");
String name = sc.nextLine();
System.out.println("请输入你女朋友的年龄");
String agestr = sc.nextLine();
int age = Integer.parseInt(agestr);
gf.setAge(age);
gf.setName(name);
break;
} catch (NumberFormatException e) {
System.err.println("数字格式有错,请重新输入");
}catch (RuntimeException e){
System.err.println("名字有误 或 年龄有误");
}
}
System.out.println("女朋友的年龄"+gf.getAge() + "女朋友名字" + gf.getName());
}
}
4.5 自定义异常
防止再出现异常时,没有适合说明异常的工具
书写步骤:
- 定义异常类
- 写继承关系
- 空参构造
- 带参构造
AgeOutAreaException
package 异常;
public class AgeOutAreaException extends RuntimeException{
public AgeOutAreaException() {
}
public AgeOutAreaException(String message) {
super(message);
}
}
NameFormatException
package 异常;
public class NameFormatException extends RuntimeException{
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
public void setName(String name) {
int len = name.length();
if (len<3 || len>10){
throw new RuntimeException(name + "范围为长度3-10");//运行时错误
}
this.name = name;
}
public void setAge(int age) {
if (age>40 || age<18){
throw new RuntimeException(age +"超出范围") ;
}
this.age = age;
}