Java学习总结
Java总结
Java简介
概述
java是一门被广泛使用的计算机编程语言,具有跨平台、面向对象、泛型编程的
特性,主要应用于企业级的WEB应用开发和移动端的应用开发
jdk版本发展
从1996年开始2020年已经发展到14版本
jdk1.2版本【开始增加java的平台版本】
jdk1.5版本【里程碑的版本:增加了泛型 自动拆装箱、枚举等主流技术】
jdk1.7版本
jdk1.8版本【目前中国市场常用的版本之一】
java的平台版本
javaME:最小的平台版本 【主要用于移动端的开发:贪吃蛇 坦克大战】
javaSE:标准平台版本【增加类库,主要应用于PC段的开发】
javaEE:企业级的版本【主要用于网站的开发】
特点:
免费开源
面向对象
编译性:源文件通过翻译变成计算机可以识别的字节码文件
动态性:运行过程中可以对数据进行修改----反射
跨平台性:同一个字节码文件可以在不同的平台上运行,借助于jvm实现
JVM、JRE、JDK
三者之间的关系
JDK=JRE+java的开发工具(javac、java、javadoc)
JRE=JVM+Java核心类库
JVM:java虚拟机,识别字节码文件
JRE:java运行环境,给java代码提供正常的环境
JDK:java开发工具包,给开发者使用
Java的使用
Path环境变量的配置
目的:
解决源文件不在bin目录下不能编译的问题
原理:
把javac.exe的路径交给系统的环境变量Path
注释的作用:
1、可以对代码进行解释说明
2、帮助开发者记录编程思路,辅助开发
3、帮助开发者迅速的定位错误代码,进行排错
标识符命名规范
内容要求:
-
大小写的英文字母
-
0-9的数字
-
特殊字符$和_
-
其他国家的语音的字符
注意事项:
-
不能使关键字
-
数字不能开头
-
中间不能出现空格
-
一般不用_开头
命名规范:
- 见名知意
- 类名:大驼峰
- 包名:全部小写,中间用‘ . ’隔开
- 方法名和变量名:小驼峰
- 常量:字母全部大写,中间用_隔开
常量:
分类:
字面值常量:本身就是对应的常量
符号常量:PI E 符号不是量本身
变量:
基本数据类型(四类八种):
整数:byte int short long
浮点数:double float
布尔:boolean
字符:char
运算符:
算数运算符
赋值运算符
比较运算符
逻辑运算符
三元运算符
位移运算符:<< 左移一个数制位,扩大两倍。>>右移缩小两倍
自动类型提升:
byte,short,char—>int—>long—>float—>double
byte,char,short变量做运算的时候用int去接受,同种类型也不可以(需要用int接收):
定义long变量的时候,数据结尾需要以L结尾:long l=123123L;当前的例子如果不加L不会编译出错,是因为不加L的时候,系统默认以为是int类型,系统默认的做了一个自动类型提升的操作,如果定义是:long l=12312312312312;就会出错。
定义float的时候数据要以f结尾,如果是float aa=12.22;编译会出错,是因为系统会默认为double,double转化为float是精度会损失,所以编译报错。
编码集:
简介:
字符和数字映射关系形成的表就叫做编码集。
GBK编码集:
一个英文字符占1个字节,一个中文占2个字节
utf-8编码集:
一个英文字符占1个字节,一个中文占3个字节
switch---case语句
注意事项:
1、传入的标准值数据类型有要求:
jdk1.5之前:只能串 byte short char int
jdk1.5时:增加枚举类型【enum】
jdk1.7版本:增加String【字符串】
2、case项后面跟的是常量,不能是变量【常量的类型和标准值的类型一致】
3、default项理论上可以写在任意位置【选择语句中case项外】
无论写在哪里都是最后匹配
4、case项的break没有特殊的需求不要省略
一旦省略会发生case项的穿透性,case项执行逻辑相同的时候可以使用穿透性
循环语句:
流程:
1、执行初始化语句
2、查看循环条件看是否成立
不成立【false】:结束循环语句
成立【true】:
3、执行循环体和初始化变量的改变
4、回归第二步执行234的操作一直到循环条件不成立结束循环语
句
方法:
概念:
java中把使用固定格式包裹的一段具有特殊含义或功能的代码段就叫做方法【函
数】
好处:
1、提高代码的复用性
2、提升代码的安全
3、提升开发效率
Jvm的内存划分
- 程序计数器(寄存器):存放本地(jvm)程序执行指令的
- 本地方法栈(本地方法区):为执行本地方法服务的
- 方法区:存放java代码的字节码文件对象,静态资源,常量池等资源
- 栈内存:专门用来执行java方法的区域
- 堆内存:存放类对象的相关数据的区域
方法的重载:
概述:
同一个类中,方法名相同,参数列表不同的方法称为方法的重载。
什么是重载:
-
参数个数不同
-
参数个数相同,参数的数据类型不同
-
参数个数相同,数据类型相同,数据类型的顺序不同
注意:方法的重载和方法的修饰符、返回值的类型没有关系
数组:
特点:
- 没创建之前可以存放任意数据类型的数据
- 一旦创建出来就只能存放指定的数据类型
- 大小固定(和集合的不同)
常见异常:
1、数组索引越界异常【ArrayIndexOutOfBoundsException】
原因:
对数组的元素进行操作的时候使用的索引值不在对应数组的索引范围内
2、空指针异常【NullPointerException】
原因:
1、数组类型的变量中没有具体的数组地址指向,还主动的使用该变量进行数
组存取值的操作
面向对象:
思想:
面向过程:注重自上而下的做事的流程包括事情的操作细节和方式
面向对象:关注自上而下的谁来做事情,关注的是做事情的对象
好处:
1、符合人的思想理念
2、把复杂的事情简单化
3、把执行者变为指挥者
特征:
封装 继承 多态
类
概述:
是对一类事物的属性(变量)和行为(方法)的描述的集合体
构造方法:
特点:
- 没有返回值类型
- 方法中一般不输出return
- 方法名和类名相同
- 直接被jvm调用
- 没有提供构造方法的时候,系统会默认提供空参构造
对象
概述:
对象就是对java描述的类的具体化
对象的创建过程:
-
加载创建对象所在的文件字节码文件对象
-
执行mian方法
- 开辟类类型的变量空间
- 加载创建对象的对应的类
-
在堆空间开辟一块新的空间(对象空间)
- 根据类的属性描述在对象空间中分别开辟对应的属性空间存放该对象的属性值
- 加载类的方法的标记值到对象空间中
- 给该空间生成空间地址值,并附值到栈空间的对象名变量空间中
成员变量和局部变量的比较:
-
定义的位置不同
局部变量在方法内
成员变量在类里方法外
-
内存中的位置不同
局部变量在栈中
成员变量在堆中
-
所属不同,声明周期不同
局部变量属于方法,局部变量随着方法的调用而加载,方法执行完毕而消失
成员变量属于类,成员变量随着对象的创建而加载,对象消失而消失
-
默认值不同
成员变量有默认值,在对象创建的是否赋予的默认值
基本数据类型
整数:0
浮点型:0.0
字符性:'\u0000'
布尔类型:boolean
引用数据类型
null
局部变量没有默认值,不赋值不能使用,会报错
变量访问参考就近原则
this和super
this--代表当前调用的对象
super----代表当前调用对象的父类引用
注意:super和this只能写在方法体的第一行
this可以调用子父类所有的成员变量和成员方法
super只能调用父类有的成员变量和成员方法
匿名对象
定义:没有名字的对象
使用场景:
-
对象只使用一次
-
使用完会及时被垃圾回收器回收
封装
概述:
-
把一些类的属性和实现细节进行封装的现象就叫封装
-
使用修饰符对要包装的资源进行修饰,限定资源可以被访问的范围
好处
提高了代码的开发效率,安全性和复用性
原则:
- 把属性和实现细节封装起来
- 对外提供统一的访问接口
属性赋值
优先级:
默认赋值>显性赋值>构造赋值>setter赋值
静态变量
特点
-
属于类不属于对象,随着类的加载而加载
-
有限于对象而存在
-
被所有对象共享使用
-
使用类名访问
静态变量和非静态变量
-
所属不同,生命周期
- 静态变量属于类,随着类的加载而加载
- 非静态变量:
成员变量属于对象
局部变量属于方法
-
内存位置不同
- 静态变量在方法区的静态区
- 非静态变量
成员变量在堆
局部变量在栈
-
访问方式
- 静态变量用类名访问
- 非静态变量
成员变量对象引用
局部变量直接用变量名
注意:静态变量不能被定义在方法内(不论是静态方法还是非静态方法)
静态方法:
注意事项:
- 静态方法不能使用非静态资源,但是可以定义
- 非静态方法可以调用静态方法
- 静态方法不能用this,this代表的是当前的对象,静态方法优于对象存在,调用静态方法的时候可能还没有创建对象
工具类
概述:
java中只有静态方法而且构造方法私有化(不可创建对象)的类就叫做工具类
Arrays
方法:
1、binarySearch(int[] arr, int key)
在 arr 数组中,查询 key 元素的索引第一次的索引
前提:数组本身是升序排列
效率:高于全部遍历
2、sort(int[] arr)
将 arr 数组进行升序排序
3、toString(int[] arr):【有返回值:String类型】
将 arr 数组中的数据,都以字符串的形式显示出来
继承
概述
类和类之间没有关系,但是一个类还想要拥有另一个类的资源
继承中的成员变量
成员变量不同名:
父类只能使用自己的
子类可以使用子父类所有的(私有化除外)
同名:
父类只能使用自己的
子类优先使用自己的,想要使用父类的需要借助super关键字
继承中的成员方法
不同名:
父类只能调用自己的
子类可以调用子父类所有的
同名:
要求子类要么省略,要么重写
重写后:
父类调用的是自己的方法
子类调用的是自己重写后的方法
重写和重载
重写:
存在于子父类继承关系中(不同类)
注意:
父类的私有方法不能重写
子类重写后的方法的权限只能大于等于父类的权限
除了修饰符其他的不能变
重载:
存在于同一个类中
方法名相同 参数列表不同
参数列表不同:
1、个数不同
2、个数相同,数据类型不同
3、个数和数据类型相同,数据类型的顺序不同
继承中的构造函数
子类不能继承父类的构造方法,但是可以调用父类的构造方法【调用父类的构造方法主要目的就是创建子类对象的时候加载继承父类的资源】
子类构造是在调用父类构造函数的时候,是在子类的对象空间中开辟了一块父类空间加载属性
继承体系
继承方式有很多:
1、单继承:一个类只能继承另外一个类【一次只能继承一个类】
2、多层继承:类A 继承 类B 类B 继承类C
3、多继承:一个类同时可以继承多个类
java中只支持单继承和多层继承不支持多继承
代码块
概述:
被花括号单独包裹的代码段就是代码块
根据位置的不同 命名也不同 功能也不尽相同
分类
局部代码块
构造代码块
静态代码块
同步代码块
局部代码块
位置:
方法的方法体中
作用:
限定局部变量的生命周期的,及时的释放空间提升代码的执行效率
执行时机:
方法被调用时执行
使用注意事项:
1、代码块内部可以定义变量但是不能定义静态变量
2、代码块可以使用外部的所有资源
3、代码块内部的资源出了代码块区域就不能被使用了
构造代码块
位置:
类中方法外【成员变量位置】
作用:
用来给对象的属性进行显性赋值
特点:
1、优先于构造方法执行
2、每次创建对象构造代码块都要执行一次
执行时机:
创建对象的时候
静态代码块
概述:
被static修饰的构造代码块就叫静态代码块
位置:
类中方法外【成员变量位置】
作用:
1、给类的静态变量显性赋值
2、用来加载那些只需要加载一次的资源【一些驱动的加载】
格式:
static {代码块内容}
执行特点:
1、随着类的加载而加载
2、只加载一次
代码块执行顺序
静态代码块>构造代码块>构造方法>局部代码块
权限修饰符
Final
修饰类:不可被继承
修饰变量:只能赋值一次,值不可变
修饰方法:不可重写,想要调用只能继承使用
Private
只可在本类中使用
默认
只可在本类,本包中使用
Protected
能在本类,本包中使用
在别的包中可以被继承,不能被直接访问
包
1、概述
就是java中用来统一分类管理代码的特殊的文件夹
特殊:
1、可以参与编译
2、包的路径编译后变为字节码文件名的一部分
比如:
Person类编译后的字节码文件的名称:
com.ujiuye.demo.Person.class
com.ujiuye.demo.Person这样的名称叫做全限定类名
2、作用:
1、管理代码
2、可以区分管理同名的类便于编译和运行
3、运行:
同包下:不需要导包
不同包:需要导包【lang包除外】
使用 import + 包路径
使用类的时候不导包的直接使用全限定类名进行使用
注意事项:
如果一个类中使用到多个不同包下的同名资源一般不建议都导包,建议一个
导包一个使用全限定类名
内部类
概述:
定义在类中的类叫做内部类
作用:
进一步的对资源进行封装使用,提升代码的安全。
分类:
根据定义的位置不同分为
局部内部类
成员内部类
普通的成员内部类
私有的成员内部类
静态的成员内部类
根据表示形式分为:
有名内部类【位置划分的内部类都属于有名内部类】
匿名内部类
总结
-
除了静态成员内部类都不可定义静态资源
-
调用
-
普通:外部类名.内部类名 对象名 = new 外部类名(参数).内部类名(参数)
-
静态:外部类名.内部类名 对象名 = new 外部类名.内部类名(参数)
-
局部:在方法中创建内部类对象使用方法调用
-
私有:外部类的外部通过创建外部类的对象调用外部类中的方法创建内部类的对象调用相应的资源
-
-
可以使用外部的所有资源(静态不可调用非静态资源)
-
外部类里(局部在方法里)创建对象访问内部类资源(静态通过类名访问)
抽象方法
概述
只有方法声明没有方法体的方法
特点
- 只对外声明不会实现的功能
- 必须由子类继承并重写
- 只存在与抽象类和接口中
抽象类
概念
被abstract修饰的类
使用
- 抽象类有构造方法但是不能创建对象
- 只能由子类继承并重写所有的抽象方法
- 可以没有抽象方法
接口
概述
用来定义规则的集合体,定义抽象方法的集合体
接口是对不同类型事物共性行为提取的定义
类是对统一类型事物共性行为进行描述
注意:
接口的属性默认public static final修饰,是一个最终静态变量,可以直接用接口名直接访问
特点:
- 没有构造方法
- 不能创建对象
- 子类重写
接口的实现
单实现:
一个类实现一个接口的情况
多实现:
一个类同时实现多个接口的现象
实现原则:
1、重写接口中所有的抽象方法
2、不同接口中相同的抽象方法只需要重写一次
继承和实现的优先级
- 继承优先实现
- 父类中的成员方法和接口的抽象方法方法声明一致了子类就不需要重写接口中的抽象方法,优先执行父类同名的成员方法
- 接口和父类中出现同名的抽象方法子类只需要重写一次
多态
概述:
事物的多种形态
Java中对象的多种形态
Java中对象对外体现的并不是自己的类型而是分类的类型形态就叫做多态
多态的前提:
必须存在继承或实现关系
多态的特点:
父类的引用指向子类对象空间的地址值
【父类类型的变量存放的是子类对象的地址值】
多态的格式 :
父类类型 对象名 = new 子类类名(参数);
多态中成员变量的访问原则
原则:
编译看左边,运行看左边
理解:
编译的时候先要看左边父类中是否有这个成员变量,有:编译通过 无:报错
运行的时候到左边父类中的成员变量的值
多态中成员方法的访问原则
原则:
编译看左边,运行看右边
理解:
编译的时候要到父类中查看是否有这个方法 有:编译通过 无:报错
运行的时候先看子类中是否重写该方法:
重写:执行子类中重写的方法体
没有重写:执行父类中的方法的方法体
引用数据类型的向上向下转型
1、向上转型:
子类对象的类型变成父类类型
多态本身就是向上转换
2、向下转型:【多态的前提下】
父类类型的多态对象的类型转换为子类类型
转型的格式:
子类类型 对象名 = (子类类型)父类类型对象
使用向下转型的时候需要判断向下转的是否是原来的类型:用 (多态对象 instanceof 类型 )判断
多态的好处
增加代码的扩展性
匿名内部类
概述:
属于内部类的表现形式划分的一种
没有名字的内部类 他和其他内部类不同
他没有去定义任何的类,他是父类的子类或接口的实现类的对象的体现形式
使用场景:
一个抽象父类或接口想要被使用,又不想书写他们的子类或实现类,就可以在测试
类中使用匿名内部类直接创建父类或父接口的子类对象。
局限性:
只能使用一次
API
定义:应用程序接口【Application Programming Interface】
接口:用于规定方法名称的规则的集合
实际:应用程序编程接口,也包含了各种实际有实现内容的方法、
类型、接口、枚举说明等内容的集合文档
理解:
实际API 就是语言源文件的帮助文档的集合文档
toString方法
Object子类没有重写toString方法的时候,调用该方法是得到的是调用对象的
地址值
Object子类重写toString方法的时候,调用该方法是得到的是调用对象属性值
jdk提供的类99%都重写了toString方法
‘==’和equals方法的区别
== :比较数据的
可以比较任意数据类型
基本数据类型:
比较的就是数据本身的大小关系
引用数据类型:
比较的是对象的地址值是否一致【Object对象比较底层使用就是 == 】
equals方法:比较的是对象
只能比较引用数类型
1、没有重写equals方法:比较的就是对象的地址值
2、重写了equals方法:比较的就是对象的属性值
Scanner
1、概述:
一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
2、构造方法:
Scanner(File f):扫描指定文件内容的扫描器对象
Scanner(String path):扫描指定的路径下的文件的扫描器对象 path:是一个文件的路径
Scanner(InputStream is):扫描指定的输入流内数据的扫描器的对象
System.in:是一个InputStream类型的对象【默认关联到键盘】
3、录入基本数据类型的方法:
nextByte():键盘录入byte类型的数字
nextShort():键盘录入short类型的数字
nextInt():键盘录入int类型的数字
nextLong():键盘录入long类型的数字
nextBoolean():键盘录入boolean类型的值
nextFloat():键盘录入float类型的数字
nextDouble():键盘录入double类型的数字
4、录入字符串类型
1、next():识别一个不带空格的字符串,碰到空格结束扫描
2、nextLine():识别一整行字符串,碰到回车结束扫描
5、 Scanner的数据交叉错误
键盘录入的数据,扫描器一次没有取完,同一个对象,下次会直接在输入流中获取剩余的数据,而不是通过键盘重新录入
解决:
不使用统一对象
不使用nextLine
使用两次nextLine
String
概述
1、他是对字符序列这个事物进行描述的类
2、每一个字符串常量都是String的一个对象
3、字符串常量存在于方法区的常量池
4、字符串对象一旦创建长度值就不变(所有的操作都不会元数据产生影响)
构造方法
1、String():创建一个内容为空的字符串对象
2、String(byte[] b):
创建一个以指定字节数组内容为内容的字符串对象
3、String(char[] c):
创建一个以指定字符数组内容为内容的字符串对象
4、String(byte[] b , int starIndex,int length):
创建一个以指定字节数组指定开始索引指定长度内容的内容为内容的字符串对象
5、String(char[] b , int starIndex,int length):
创建一个以指定字符数组指定开始索引指定长度内容的内容为内容的字符串对象
length : 必须要在 数组长度值-开始索引值 范围内
6、String(String s):
创建一个以字符串s为内容的字符串对象
直接赋值和构造方法创建的区别
1、直接赋值发法不需要在堆空间开辟空间,变量直接指向常量池中的常量【每个字符串常量在常量池中只有一个】
2、构造方法创建需要堆空间创建新的空间的,生成对象的地址值的,变量中存放的是地址值【指向的堆空间】
常用功能
判断功能
equals(String s):比较两个字符串是否一样
equalsIgnoreCase(String s):忽略大小写比较两个字符串是否一致
contains(String s):判断调用字符串中是否包含指定的字符串s
startsWith(String s):判断调用字符串是否以指定字符串开始
endsWith(String s):判断调用字符串是否以指定字符串结尾
isEmpty():判断调用字符串内容是否为空
获取功能
length():获取调用字符串对象的长度
charAt(int index):获取字符串对象指定索引上的字符
substring(int index):获取指定字符串对象从指定索引开始到结尾的所有内容
substring(int startIndex,int endIndex):
获取指定字符串对象从指定开始索引到结束索引之间的内容【索引含头不含尾】
indexOf()家族:默认从左往右找
indexOf(int char):获取指定的字符在调用字符串中第一次出现索引值
indexOf(int char,int startIndex):
获取指定的字符在调用字符串中从指定索引后面内容中第一次出现索引值
indexOf(String s):获取指定的字符串在调用字符串中第一次出现索引值
indexOf(String s),int startIndex):
获取指定的字符串在调用字符串中从指定索引后面内容中第一次出现索引值
lastIndexOf()家族:默认是从右往左找
功能和indexOf家族的功能一一模一样
转换功能
getBytes():字符串转换为字节数组
toCharArray():字符串转换为字符数组
toUpperCase():把字符串的内容变为全部大写
toLowerCase(): 把字符串的内容变为全部小写
concat(String s2):拼接两个字符串
其他方法
replace(String oldStr,String newStr):
使用指定的newStr去替换字符串对象中oldStr的内容
trim():去除字符串对象两端的空格或制表符
System类
概述:
系统类,基本描述了和系统相关的资源 他是最终类
常用字段:
err:标准错误输出流【字体颜色是红色】
in:标准输入流
out:标准输出流【字体颜色是黑色】
常用方法:
gc():调用垃圾回收线程回收垃圾【对象】
currentTimeMillis():获取当前时间的毫秒值
通过重写finalize方法可以查看垃圾回收器是否运作:
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("垃圾回收线程执行了");
}
Math类
概述:就是一个操作数学基本运算的类 是一个拥有方法是静态方法的类 【工具类】
成员变量:静态最终变量
E:具有一个固定值【自然数 2.718】
PI:具有一个固定值【圆周率 3.14159265358】
方法:
abs(double num):获取一个小数的绝对值
cbrt(double num):获取一个小数的立方根
sqrt(double num):获取一个小数的平方根
ceil(double num):向上获取一个小数最接近他的整数
floor(double num):向下获取一个小数最接近他的整数
max(double num1,double num2):获取两个小数的最大值
min(double num1,double num2):获取两个小数的最小值
pow(double num1,double num2):获取num1的num2次方【幂】的结果
random():获取0.0到1.0之间任意一个小数
round(double num):获取一个小数四舍五入后的整数【只针对第一位小数】
log(double num):获取以自然数为底数的对数
log10(double num):获取以10为底数的对数
StringBuilder
概述:
他也是用来描述字符串的类【另外一个表示字符串的形式】
通常叫做字符串缓冲区
特点:
1、可变的字符串表现形式
2、他提供的功能对字符串的操作就是在字符串本身操作
StringBuilder和String对比:
1、相同点:
都可以表示字符串
2、不同点:
1、String一旦创建不可变【固定的字符串】
2、StringBuilder是一个可变的字符串【字符串】
3、String对字符串的改变生成全新的字符串对象出来
4、StringBuilder对字符串的改变就是改变字符串本身
构造方法
空参构造
StringBuilder():创建一个默认空间大小16的字符串缓冲区对象
默认空间:缓冲区的空间 16
字符串长度:0
有参构造
StringBuilder(int len):创建一个指定空间大小len的字符串缓冲区对象
空间大小:缓冲区的空间 len
字符串长度:0
StringBuilder(String s):
创建一个空间大小为默认大小16+字符串的长度的字符串缓冲区对象
空间大小:16 + s.length()
字符串长度:s.length()
缓冲区大小会根据操作的字符串的长度进行改变【会自我维护】
成员方法
获取功能
capacity():获取缓冲区对象的空间的大小
length():获取缓冲区中操作的字符串的长度
添加功能
append(Object o):添加指定元素o到缓冲区中字符串的尾部
insert(int offset,Object o):
添加指定元素o到缓冲区中字符串的指定索引位置
特点:
1、不是覆盖行为【插入的索引对应的元素往后移动一位】
2、插入到指定索引的前面,几乎所有的插入操作都是插入索引的前面
删除功能
deleteCharAt(int index):
删除缓冲区中字符串的指定索引的字符【删除一个元素】
delete(int starindex, int endindex):
删除缓冲区中字符串的指定索引范围内的内容
注意:
1、索引含头不含尾的操作
2、最大的索引值没有要求【大于最大索引默认删除到最后】
替换功能
replace(int start, int end, String str):
使用指定的内容str替换缓冲区中字符串的指定范围内的内容
注意:
1、替换的内容从左边开始替换 一次只能替换一个
2、索引还是遵循含头不含尾
3、最大的索引值使用的时候没有限定【大于最大索引默认取到最后元素】
反转功能
reverse():
可以把缓冲区中的字符串内容进行反转
转换为字符串功能:
String变成StringBuilder:
1、StringBuilder的构造方法
2、append方法和insert方法
StringBuilder变成String :
toString方法
StringBuilder和StringBuffer的对比
区别:
相同点:
1、都是可变字符串表现形式
2、都是字符串缓冲
不同点:
1、出现的时间不一样
StringBuffer:在jdk1.0出现
StingBuilder:在jdk1.5出现
2、线程安全性不同
StringBuffer:线程安全性比较高
StingBuilder:线程安全性比较低
3、效率不同
StringBuffer:效率低
StingBuilder:效率高
包装类
概述:
单个数字操作的时候没有相关的功能,有的时候想要让数字具备一定的功能,想办法把数字对应的描述形成的对应的包装类
基本数据类型对应引用数据类型
主要就定义了基本数据类型和字符串以及包装类之间相互转换的功能
基本数据类型【四类八种】 包装类
byte --------------------- Byte
short --------------------- Short
int --------------------- Integer 【特殊】
long --------------------- Long
float --------------------- Float
double --------------------- Double
char --------------------- Character【特殊】
boolean --------------------- Boolean
Integer
概述:
他是int的包装类 维护一个int类型的属性
定义了能操作数字的相关功能
构造方法
Integer(int num):
把int的数字转换为Integer对象
Integer(String s):
把字符串类型的的数字转换为Integer对象
字符串只能传递字符串类型的数字 比如 "123" 不能是 "金莲"
成员方法:
intValue():把Integer对象中的数值变为int类型的数字 //有自动拆装箱,基本用不到
静态方法:
parseInt(String s):把字符串类型的数字转变为int类型的数字
toBinaryString(int i):把数字转换为二进制的数字的字符串表示
toOctalString(int i):把数字转换为八进制的数字的字符串表示
toHexString(int i ):把数字转换为十六进制的数字的字符串表示
toString(int i, int radix):
把数字转换为指定数制的数字的字符串表示
radix :就是要转换的数制的具体的值
valueOf(String s):
把字符串转换为Integer的的对象
valueOf(int i):
把int数字转换为Integer的的对象
自动拆装箱
拆箱:把包装类里面的数字变为对应的基本数据类型的数据的过程
装箱:把基本数据类型的数字变为对应的引用数据类型的对象的过程
自动拆装箱:【jdk1.5之后新增的特性】
自动装箱:可以把基本数据类型的数据直接赋值给对应包装类类型的变量
自动拆箱:可以把包装类对象直接赋值给对应的基本数据类型变量
比如:
Integer i = 123; 自动装箱
int i2 = i; 自动拆箱
常量
MAX_VALUE:代表int数据类型的存储的最大的数据值
MIN_VALUE:代表int数据类型的存储的最小的数据值
SIZE:32
TYPE:维护的对应的基本数据类型的执行的对象类型【反射对象】
正则表达式
1、特殊字符:
\\ : 代表 \
\t : 制表符 tab键的内容
\r : 新行
\n : 换行
2、字符类型:
使用[]来表示,表示一个字符
比如:
[abc] :表示有且只有一个字符字符必须是abc三个字符中任意的一个
[^abc] :表示有且只有一个字符字符必须是除了abc三个字符以外任意的一个
[a-zA-Z]:表示有且只有一个字符字符必须在指定的范围内的字符中的一个
3、预定义字符
\\. 代表符号.
. 任意字符
\d 数字:相当于 [0-9]
\D 非数字: 相当于[^0-9]
\s 空白字符:相当于 [ \t \n \x0B \f \r]
\S 非空白字符:相当于[^\s]
\w 单词字符:相当于[a-zA-Z_0-9]
\W 非单词字符:相当于[^\w]
4、数量词
模糊的:【X表示数量词修饰的字符】
X? 表示X字符出现1次或者0次
X* 表示X字符出现0次或多次
X+ 表示X字符出现1次或多次
精确的:使用{}表示精确 n和 m是具体的数字
X{n} X字符恰好出现 n 次
X{n,} X字符至少出现 n 次
X{n,m} X字符至少出现 n 次,但是不超过 m 次
5、正则表达式的方法
matches(String regex):判断当前字符串和正则表达式匹配
split(String regex):使用指定的正则表达式切割字符串
replaceAll(String regex ,String replacement):
将符合正则表达式的字符串全部替换为参数指定的字符串
集合
定义:
用来存放多个引用数据类型的数据的可变容器叫做集合
特点
- 只能存放引用数据类型(存入数字等基本数据类型的时候是通过自动拆装箱封装为了对应的对象类型)
- 同时存放不同的数据类型的对象
- 长度可变
集合体系
单列集合【Collection】单列集合的顶层接口
有序集合【List】有序,有索引,可重复
ArrayList:顺序存储,查询快
LinkedList:链式存储,删除快
Vector【集合被淘汰了】线程是安全的,用法同ArrayList
无序集合【Set】无序,无索引,元素唯一
HashSet 底层是哈希表
LinkedHashSet:底层是哈希表加链表,有序,无索引,元素唯一
TreeSet【很少使用】:
双列集合【Map】
HashMap
LinkedHashMap
集合和数组的区别
1、存放的数据类型不一样
数组:任意的数据类型
集合:引用数据类型
2、创建后存放的数据不一样
数组:单一的数据类型数据
集合:混合的引用数据类型数据
3、容器的长度不一样
数组:长度固定
集合:长度可变
Collection
概述:
单列集合的顶层接口,在这个接口中定义了所有单列集合共性的功能。
常用方法
add(E e):添加元素到集合中
remove(Object o):删除集合中指定的元素
clear():清空集合中所有的元素
contains(Object o):判断集合中是否包含指定的元素
size():获取当前集合中元素的个数【获取集合的长度】
isEmpty():判断集合中是否为空
All方法
addAll(Collection<? extends E> c):
添加一个指定集合中的全部内容到调用的集合中
removeAll(Collection<? extends E> c):
删除调用集合中包含指定集合的元素
containsAll(Collection<? extends E> c) :
判断调用集合是否包含指定集合的内容
retainAll(Collection<? extends E> c):
保留调用集合中包含指定集合的内容
数组法遍历
// 数组法遍历集合获取元素
// 集合转变为数组
Object[] arr = list.toArray();
// 遍历数组
for (int i = 0; i < arr.length; i++) {
// 获取到数据并输出
// String s = (String)arr[i];
Object s = arr[i];
System.out.println(s);
}
注意:
把集合中的数据的数据类型转换为Object类型,遍历出来之后有可能需要进行向下转型
迭代器法遍历
迭代器:Iterator
拥有两个方法配合使用完成遍历
hasNext():判断下一个位置是否有元素
next():
1、获取位置上面的元素
2、获取元素的同时移动迭代器的指针到下一个位置
遍历的步骤:
1、集合获取迭代器的对象【通过iterator()获取】
2、迭代器的对象调用hasNext方法判断位置是否有元素
3、next方法根据判断的结果去取值:
有值:就调用next方法取出来
没值:不取【不用调用next方法】
注意:迭代器的这两个方法需要和循环配合使用【配合while循环】
// 迭代器遍历
// 集合获取迭代器的对象
Iterator it = list.iterator();
// 开始遍历
while (it.hasNext()) {
Object s = it.next();
System.out.print(s + " ");
}
迭代器遍历注意事项:
1、hasNext方法和next方法调用一次执行一次
2、hasNext方法整个遍历中执行次数比next方法多一次【next方法执行次数和集合的长度一致】
3、next方法执行的时候只能执行一次【在hasNext方法的判断下】
4、next方法移动迭代器的指针
5、hasNext方法通过指针进行判断
List
特有方法
add(int index ,Object o):
添加指定元素到指定的位置上
remove(int index) :删除指定索引上的元素
set(int index ,Object o):
修改指定元素到指定的索引位置上
get(int index):
获取指定索引位置的元素
List特有遍历
// List的特有遍历
for (int i = 0; i < list.size(); i++) {
// i代表集合的索引值 获取集合的元素 get(i)
System.out.print(list.get(i) + " ");
}
遍历容易出现的问题:
实例:
public static void main(String[] args) {
ArrayList<Integer> arrayLists=new ArrayList<>();
arrayLists.add(1);
arrayLists.add(2);
arrayLists.add(2);
arrayLists.add(2);
arrayLists.add(5);
// Iterator it= arrayLists.iterator();
// while(it.hasNext()){
// Integer i= (Integer) it.next();
// if (i==2)it.remove();
// System.out.println(i);
// }
for(int i=0;i< arrayLists.size();i++){
if(arrayLists.get(i)==2)arrayLists.remove(i);
}
System.out.println(arrayLists);
}
问题:这里想要删除集合中的2元素,运行下来却发现没有删除干净
原因:删除元素的时候,集合的整体前移,i相当于指向了下下个元素,导致跳过了元素
解决:
- 每一次删除都 i-- ,让指针往回倒一下
- 遍历的时候从后往前遍历
- 用迭代器遍历和删除
并发修改异常
原因:
在使用迭代器遍历的过程中使用集合的对象对集合的元素进行了增删的操作引起的
异常
解决:
1、不使用迭代器遍历
2、遍历使用迭代器对象进行增删
删除:Iterator的对象的remove方法就可以完成删除
增加:ListIterator的对象的add、remove方法就可以完成增加、删除
// 迭代器遍历集合
// 获取集合的迭代器对象
// Iterator it = list.iterator();
ListIterator it = list.listIterator();
// 开始遍历
while (it.hasNext()) {
Object object = it.next();
System.out.println(object);
it.remove();
it.add("123");
}
注意
迭代器遍历的时候,集合元素删除了倒数第二个元素不会导致并发修改异常。
原因:当迭代器通过 next() 方法返回元素之前都会检查集合中的 modCount (表示集合的修改次数)和最初赋值给迭代器的 expectedModCount 是否相等,如果不等,则抛出并发修改异常。当删除倒数第二个元素的时候,最后一个元素往前移动,指针指向了最后,这时候就不会运行next函数,也就不会报错。
ArrayList
存储方式:
底层使用数组数据结构来存储数据,特点通过索引区分数组数据结构的位置进行数
据存取操作
数组数据结构他是一个整体操作的时候遵循整体的结构特点
特点:
查询快,增删慢
查询快:数据结构是一个整体,查询的时候告诉索引值,直接定位于位置,查询到没有对数据的整体造成任何的影响
增删慢:数据结构是一个整体,增删的时候在指定的位置增加位置或减少一个位置,指定位置后面的部位整体发生移动所以增删就比较慢
LinkedList
特点:
查询慢 增删快
存储方式:
底层使用的链表数据结构进行存储数据的。
查询慢:链表的每一个结都一样,查询需要一个一个的去找
增删快:找到一个位置只要改变两个结中的地址的指向
特有方法:
addFirst(Object o):添加元素到集合的头部
addLast(Object o):添加元素到集合的尾部
removeFirst():删除集合头部的元素
removeLast():删除集合的尾部元素
getFirst():获取集合的头部元素【不会删除头部元素】
getLast():获取集合的尾部元素
pop():弹出集合的头部元素【会删除头部的元素】
push():添加元素到集合的头部
范型
概述:
提前使用未来的数据类型,这个未来的数据类型就叫做泛型
使用<大写字母>方式来充当未来的数据类型
大写字母可以随便写 可以是一个也可以是多个 一般使用一个 常用:E T
使用:
1、声明泛型【让泛型存在】
2、使用泛型定义相关的功能和资源
3、实例化泛型【要真正真正使用确切的数据类型】
好处:
1、提高数据的安全性。可以将运行的异常提前到编译时发现处理
2、避免强转
泛型类
概述:
含有泛型的类就是泛型类
格式:
修饰符 class 类名 <泛型1,泛型2....>{}
泛型类的泛型实例化时机:
创建对象的时候实例化泛型的具体的数据类型【泛型只能代表引用数据类型】
没有人为的指定具体的数据类型的时候,系统就默认泛型的实例化类型是Object
泛型方法
概述:
拥有泛型的方法就叫做泛型方法
格式:
修饰符 <泛型> 返回值类型 方法名 (参数列表){方法中就可以使用泛型}
注意事项:
1、普通方法如果自己没有声明泛型,可以使用所在类声明的泛型
2、静态方法如果没有声明泛型,方法中就不可以出现任何的泛型【只能使用自己声明的泛型】
3、静态方法声明泛型的时候必须把泛型声明在static的后面
泛型方法的泛型的实例化时机:
方法在调用的时候实例化泛型
泛型接口
在接口名后面声明泛型
泛型示例化时机:
1、子接口或实现类继承或实现接口的时候指定具体的数据类型
2、创建实现类对象的时候必须指定具体的数据类型
比如:ArrayList创建对象的时候指定具体的数据类型
泛型通配符
概述:
泛型通配符使用 <?> 来表示
无论是泛型还是泛型通配符都可以代表任意的引用数据类型
泛型是自己主动定义,泛型通配符是被动接收的。一般的泛型通配符用在方法的参数列表中,限定可以使用的泛型
泛型通配符的权限:
上限: <? extends 类名>
传入的数据的未来数据类型必须是类以及类的子类类型的对象
下限:<? super 类名>
传入的数据的未来数据类型必须是类以及类的父类类型的对象
Set
Set集合的数组遍历
数组法:【很少用】
1、toArray():把集合转变为Object类型的数组再进行遍历
转换完集合的数据的类型变成Object不是我们想要的
2、toArray(T[] t):把集合转变为数据类型对应的类型的数组进行遍历
步骤:
1、把集合变为数组
2、for循环遍历数组
注意:
指定的数组的长度和集合的长度一致:
转换的时候就直接使用传入的数组进行遍历
指定的数组的长度比集合的长度短:
转换的时候就根据指定的数组的数据类型和集合的长度为依据创建一个对应
的新数组来进行转化
指定的数组的长度比集合的长度长:
转换的时候就直接使用传入的数组进行遍历,多余的的位置使用null值填满
迭代器法
步骤:
1、获取迭代器对象【调用iterator方法】
2、使用while循环用迭代器的hasNext为条件,next为方法体去获取集合
的元素
注意事项:
遍历的过程中不能使用集合对象对集合元素进行增删操作
增强for
格式:
for(数据类型 变量名 :集合名称){对获取到的元素的操作的代码}
格式解释:
数据类型:指的是遍历的集合中存放的数据的数据类型
变量名:用来承载每次遍历得到的元素
集合名称:要进行遍历的集合对象
注意:
1、增强for遍历本质是迭代器遍历
2、增强for遍历过程中不能使用集合对象对集合元素进行增删操作
3、同时也不能使用迭代器对象进行增删(for循环底层的迭代器跟创建的迭代器不是一个)
HashSet保证元素唯一性的原理
1、使用存放的对象调用hashCode方法去和集合中已经存在的对象【数据】的哈希值进行对比:
不一致:直接添加该数据到集合
有一样的哈希值:
不能确定两个对象就是一样的对象进一步进行判断
2、调用equals方法比较这两个对象的属性值是否一样
不一样:直接存放到集合
一样:不存放
HashSet集合底层存放数据的数据结构
底层结构:
HashSet集合底层结构:
jdk1.8之前:数组 + 链表
jdk1.8之后:数组 + 链表 + 红黑树【二叉树】
记住:
红黑树是一个平衡二叉树,特点:查询特别快
Map
概述:
他是双列集合的顶层接口,定义了双列集合的共性功能
每个位置上存放的是键值对数据【一对数据】,这对数据是有映射关系(一对一的关系)
键值对的特点:
键:集合中的键不能重复【必须唯一】
值:可以重复
常用方法
put(K k,V v):添加一对数据到map集合中【修改指定key的value】
remove(K k):删除指定的key【键】对应的一对键值对数据
size():获取当前集合的长度
get(K k):通过指定的key【键】获取对应的值【value】
containsKey(Object o):
判断集合的键中是否包含指定的元素
containsValue(Object o):
判断集合的值中是否包含指定的元素
遍历
概述:
双列集合不能直接遍历,把双列集合变为单列集合
遍历单列集合间接获取双列集合的数据达到遍历的效果
1、键找值方式:
思路:
1、先获取map集合的所有的key【键】放到set集合中
通过方法:keySet() 就能获取到key的set集合
2、遍历key所在的set集合得到key通过key去得到对应的值
举例
// 键找值
// 获取key的set集合
Set<String> set = map.keySet();
// 遍历set集合
for (String key : set) {
// 通过key获取对应的value
String value = map.get(key);
System.out.println(key + " : " + value);
}
2、键值对方式:
原理:
把集合中的一对数据转变成类对象的属性值中,相当于一对数据对应一个类对象,把所有的类对象获取到放到set集合中,遍历set集合得到每一个对象
通过getKey和getValue方法获取到对应的属性值【集合的键和值】达到遍历的效果
entrySet():属于集合的方法 获取所有的类【Entry】对象
getKey():属于entry对象的方法 获取key值
getValue():属于entry对象的方法 获取value值
举例:
// 键值对
// 获取entry对象的set集合
Set<Entry<String, String>> entrySet = map.entrySet();
// 遍历entryset集合得到每一个对象
for (Entry<String, String> entry : entrySet) {
// 通过entry对象的getkey和getValue方法获取key和value
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
Collections类
概述:
一个专门用来定义操作单列集合相关功能的工具类
常用功能
int binarySearch(List<E> list, E e ):
在一个有升序顺序的 List 集合中,通过二分查找寻找元素e的索引
前提:操作的集合要升序排列
int frequency(Collection<E> c, E e):返回在集合 c 中的元素 e 的个数
max、min:获取集合的最大值或者最小值
replaceAll(List<E> list, E oldVal, E newVal):将集合List中的所有指定老元素oldVal都替换成newVal
reverse(List<E> list): 将参数集合 list 进行反转
shuffle(List<E> list): 将 list 集合中的元素进行随机置换
swap(List<E> list, int a, int b): 将 a 索引和 b 索引的元素进行交换
sort(List<E> list):对list集合的元素进行升序排序
synchronizedXxx 方法系列:
Xxx:转换那种类型集合 就是类型 比如:List
将一个线程不安全的集合传入方法,返回一个线程安全的集合
unmodifiableXxx 方法系列:
将一个可修改的集合传入方法,返回一个不可修改只读的集合
异常
概述:
java中代码在运行过程中出现的错误和不正常现象
对于异常现象java使用类进行描述的,出现异常使用类对象进行体现
常见异常:
1、索引越界异常
【ArrayIndexOutOfBoundsException】
【IndexOutOfBoundsException】当对数组的索引值为负数或大于等于数组时抛出
2、空指针异常:
【NullPointerException】在要求使用对象的地方使用了null抛出,使用对象未初始化
3、类型转换异常【多态的向下转型】
【ClassCastException】
4、无此元素异常【迭代遍历是多次调用next方法】
【NoSuchElementException】
5、除数为零异常【除法运算时除数为0】
【ArithmeticException】
6、并发修改异常
【ConcurrentModificationException】迭代器遍历的时候使用集合对象进行增删操作。
7、数字格式化异常【字符串转基本数据类型不是数字】
【NumberFormatException】
体系
Throwable:他是异常体系的顶层父类 定义了所有异常的共性的属性和行为
Error:错误类 统一管理 错的现象的资源
错误的现象程序员不能使用代码来捕获处理的【只能去避免】
比如:栈溢出错误
Exception:管理不正常的现象 可以使用代码获取进行处理根治的
RunTimeException:运行时异常
运行后产生的异常交给RunTimeException管理
可以去处理也可以不处理【开发的时候基本不处理】
异常处理
1、 声明异常
使用关键字throws把异常的类型在方法的参数列表后声明出去,把异常抛给调用者处理
2、捕获异常
try---catch---finally 自己处理,处理完后面的程序可运行
注意事项:
1、多个异常同时发生的时候以第一个异常捕获为主
2、异常之间存在继承关系,顺序书写保证子类类型的捕获写在前面,父类类型的捕获写在后
3、当发生异常的时候捕获的时候优先使用匹配到的本类型异常捕获, 如果没有使用父类类型的异常catch去捕获,如果父类也没有交给 jvm处理
4、无论catch块写多少个发生异常的时候只会执行一个【第一个发生异常的类型】
5、finally中的代码不管异常是否处理了都会执行,通常用来关闭流
6、jdk1.7之后多个catch项的处理方案一致的可以使用一个catch项同时捕获多个异常,异常的类型使用 | 关系来连接
jvm的异常处理机制
jvm处理异常的方式:
1、接收到异常时首先停止异常所在代码运行
2、使用捕获处理的机制将异常的相关信息打印到控制台
日常的声明异常处理,中间没有人为的捕获处理最终都到jvm,jvm就会进行相关的处理。
编译异常和运行异常
编译异常:归Exception管理
在代码编译的过程对代码的格式和语法进行相关的验证,格式和语法不对及时的报错,这中异常就叫做编译异常【编译报错的异常就是编译异常】
编译异常必须要处理,不出代码无法继续执行
运行异常【RunTimeException】
在代码的编译的时候发现不了语法和格式的异样,只有代码在执行的时候才会出现的异常
运行异常一般可处理可不处理,一般开发选择不处理
throw和throws
throws:抛出的意思
一般用于声明异常的处理,在方法的参数列表后面抛出异常的数据类型
抛出的类型有可能会发生异常也有可能根本不会出现异常
throw: 抛出的意思
一般用于抛出异常的对象使用,在方法的方法体中抛出具体的异常的对象。
一般用于定义异常发生的
异常体系中的常用方法
构造方法:
Throwable():创建一个没有任何信息的异常对象
Throwable(String message):创建一个具有异常信息描述的异常对象
Throwable(Throwable cause):创建一个具有产生原因的异常对象
成员方法:
getCause():获取调用对象的产生的原因
getMessage():获取调用对象的异常描述信息
toString():返回调用对象的所有信息
printStackTrace():打印调用对象的栈轨迹到控制台
代码实例
public class DemoThrowTest {
public static void main(String[] args) {
Throwable t2=new Throwable("wdnmd");
Throwable t3=new Throwable(t2);
System.out.println(t2.getMessage());
System.out.println(t2.toString());
System.out.println(t2.getCause());
t2.printStackTrace();
System.out.println(t3.getCause());
System.out.println(t3.toString());
System.out.println(t3.getMessage());
t3.printStackTrace();
}
}
自定义异常
自定义编译异常:
1、创建一个类【类名必须以Exception结尾】
2、使用该类继承Exception
3、提供构造方法即可
自定义运行异常
1、定义一个类【类名必须以Exception结尾】
2、去继承RunTimeException
3、提供构造方法
代码实例
//运行异常
public void setAge(int age) {
if (age < 0) {
throw new AgeRunTimeException("这个年龄小了");
}else {
this.age = age;
}
}
//编译异常
public Person(int age) throws AgeException {
super();
if (age > 150) {
throw new AgeException("你输入的年龄值太大了");
}else {
this.age = age;
}
}
File类
概述:
文件类就是java中对磁盘中的文件的描述的类
File是磁盘文件在java中的虚拟化
使用java的对象来对文件进行示例化【使用相关功能】
理解:
- 一个File对象对应磁盘中一个具体的文件
- file对象存在不代表对应文件你一定存在
- 磁盘文件存在的一定可以创建对应的File对象
File构造方法
File(String path):
创建一个指定路径的文件的对应的File对象
File(String parent, String child):
创建一个以指定的两个路径的拼接路径的文件对应的File对象
File(File parent, String child):
创建以parent文件对象的地址和child拼接后的地址对应的文件的File对象
创建方法
boolean createNewFile():
在File对象的路径中创建对应的磁盘文件
【磁盘中已经有了该文件就不创建了返回false 没有进行创建返回true】
注意:创建新文件的时候保证所在的目录必须要在磁盘中真实存在
boolean mkdir():创建单级文件夹
注意:创建新文件的时候保证所在的目录必须要在磁盘中真实存在
boolean mkdirs():
创建多级文件夹
总体注意:
一个对象调用方法操作的文件就是磁盘中对应路径的文件
删除
delete():删除调用者文件对象对应的磁盘中的文件夹或文件
注意:
1、只能删除空的文件夹
2、删除不走回收站
重命名方法
renameTo(File dest)
把调用文件的名字更换为参数对象的名字
注意事项:
1、在同文件夹下使用该方法是改名的操作
2、不在同一个文件件下该方法是改名并剪切的行为
判断功能
exists():判断当前调用者 File 对象是否存在
isFile():判断当前调用者 File 对象是否是文件
isDirectory():判断当前调用者File对象是否是文件夹
前提:调用的File对象对应的磁盘文件必须要存在如果不存在返回的值是false
获取功能
getAbsolutePath():获取当前 File 对象的绝对路径
getPath():获取的就是在构造方法中封装的路径
getName():
获取最底层的简单的文件或者文件夹名称
【不包含所造目录的路径】
length():获取文件的字节个数
该方法被文件File对象调用时,返回的是文件的字节个数
该方法被文件夹File对象调用时,返回的数据是不确定的
注意:
文件夹没有大小,length基本给文件的文件对象使用
String[] list():
获取当前文件夹下的所有文件和文件夹的名称,到一个
字符串数组中
File[] listFiles():
获取当前文件夹下的所有文件和文件夹的 File 对象,
到一个 File 对象数组中
IO流
概述
java中用来承载和运输数据的流
体系分类
从流向划分:
输入流
输出流
从功能上划分:
字节流
字符流
实际使用把两种划分进行结合形成IO流的体系:
以功能为主流向为辅:
字节流:
字节输入流
字节输出流
字符流:
字符输入流
字符输出流
字节流
InputStream
概述:
他是字节输入流的顶层父类,但是他是一个抽象类 他定义了字节输入流的共性功能
常用功能
int read():
一次读取一个字节数据到内存
int read(byte[] bytes):
一次读取多个字节到字节数组,把字节数组的内容读入到内存
【理解:使用容器字节数组去读取多个字节数据】
返回值:是读取到的有效内容的个数 【不会超出字节数组的长度】
int available():
返回没有读取的字节的个数
close():
关闭流对象
FileInputStream
概述:
文件字节输入流,他是内存和磁盘文件之间进行读取交互的io流
构造方法:
FileInputStream(File file):
创建一个以file对象对应的文件为目标文件进行读取的流对象
FileInputStream(String path):
创建一个以path地址对应的文件为目标文件进行读取的流对象
注意事项:
1、同一个io流对象在去取文件内容的时候,读取走内容后光标对应的往后移动读取走的内容个数
2、当内容已经被读取完毕再读取的时候返回值是-1
OutputStream
概述:
他是字节输出流的顶层父类 他是一个抽象类 发他定义了字节输出流的共性的功能
常用功能
void write(int b):
输出一个字节数据到指定的文件中
void write(byte[] arr):
输出一个字节数组中的所有的字节数据到指定的文件中
void write(byte[] arr, int offset, int len):
输出一个字节数组指定字节数据到指定的文件中
offset:输出字节数组的开始的索引值
len:指的是要输出的字节数据的个数
传入的时候数值不能大于 数组长度-开始索引
void close():关闭流对象
FileOutputStream
概述:
文件字节输出流 他是OutputStream的子类 功能就是字节输出流的功能是内存和磁盘文件的输出交互的流对象
构造:
FileOutputStream(File file):
创建一个以file对象对应的文件为目标文件进行写入的输出流对象
FileOutputStream(File file,boolean b):
创建一个以file对象对应的文件为目标文件进行是否追加写入的输出流对象
FileOutputStream(String path):
创建一个以path路径对应的文件为目标文件进行写入的输出流对象
FileOutputStream(String path,boolean b):
创建一个以path路径对应的文件为目标文件进行是否追加写入的输出流对象
注意事项:
1、字节输出流的对象创建的时候检查操作的文件是否存在【文件所在的文件夹真
实存在】:
不存在:自动创建文件出来
存在:不创建文件但是会对文件进行格式化,不想格式化使用追加续写功能创建io流对象
文件拷贝
一个一个读:
// 边读取边输出
// 定义一个变量承载每次读到的内容
int b ;
while ( (b = fis.read())!= -1) {
// 把每次读到的字节写出到目标文件
fos.write(b);
}
一次读多个:
// 边读取边输出
// 定义一个变量承载每次读到的内容有效字节个数
int b ;
byte[] bs = new byte[1024];
while ( (b = fis.read(bs))!= -1) {
// 把每次读到的字节写出到目标文件
fos.write(bs,0,b);
}
字节缓冲流
概述:
字节缓冲流他就是来对基本的字节流进行提效使用的。他本身没有操作数据的功能
构造:
BufferedInputStream(InputStream is):
创建一个参数is字节输入流提效的高效流对象
BufferedOutputStream(OutputStream os):
创建一个参数os字节输出流提效的高效流对象
字节输出缓冲流的特有方法:
flush():刷新缓冲流的缓冲区
flush方法和close方法的区别:
1、flush方法执行后流对象继续存在继续可以使用,flush主要的作用是刷新缓冲流的缓冲区
2、close方法执行后流对象不在了不能继续使用,close方法主要作用关闭流对象
【close方法关闭字节输出缓冲流的时候先调用flush方法刷新缓冲区然后关闭流流对象】
原理:
字节输入缓冲流:
使用字节输入缓冲流调用read方法去目标文件读取字节内容的时候:
1、先在内存的一个位置上创建一个长度为8192的字节数组
2、然后到目标文件直接读取8192个字节回来放到字节数组中
3、read读几个字节从数组中拿去对应的字节个数会内存
第二次的调用read方法读取的时候不用去目标文件读取优先在数组中获取对
应的字节个数,重复的到数组中读取,一直到数组的8192个字节取完,缓冲
流对象再到目标文件读取8192个字节回来供read方法读取
节省了流对象在目标文件和内存之间来回传输数据的时间就提效了
8192个长的字节数组就是所谓的缓冲区
字符流
概述:
解决中英文问题
Reader
常用方法
read():一次读取一个字符到内存中
read(char[] arr):一次读取多个字符到数组,把数组中的内容读到内存
close():关闭流对象
FileReader
构造方法
FileReader(File file):
创建一个以file对象对应的文件为目标读取文件的字符输入流对象
FileReader(String path):
创建一个以path路径对应的文件为目标读取文件的字符输入流对象
Writer
常用方法
write(int c):
写出单个字符到目标文件
write(String str):
写出字符串到目标文件
write(char[] arr):
写出整个字符数组的字符到指定的文件
write(char[] arr, int offset, int len):
写出字符数组中指定范围的字符到指定的文件
close():
关闭流对象
flush():
刷新缓冲区
注意:字符输出流自带缓冲区
FileWriter
构造:
FileWriter(File file):
创建一个以file对象对应文件为写出目标文件的是字符输出流对象
FileWriter(File file,boolean b):
创建一个以file对象对应文件为写出目标文件是否续写的字符输出流对象
FileWriter(String path):
创建一个以path路径对应文件为写出目标文件的是字符输出流对象
FileWriter(String path,boolean b):
创建一个以path路径对应文件为写出目标文件是否续写的字符输出流对象
字符流文件拷贝
概述:
图片不是文字组成,图片组成的字节在字符集中没有对应的字符,字符流操作非纯文本文件的时候无法完成字符的转换,字符流不能操作非存文本文件【图片、音频、视频等文件】
字符缓冲流
构造
BufferedReader(Reader r)
BufferedWriter(Writer w)
特有方法
字符输入缓冲流【BufferedReader】:
readLine():一次读取一行内容
注意:一行不是单纯电脑眼睛看的一行
字符输出缓冲流【BufferedWriter】:
newLine():换行 【“\r” “\n” “\r\n”】
注意事项
输入流和输出流同时操作的是同一个文件,两个流对象不能同时创建,输出流对象一定要在读取内容完毕后创建。不然会把文件格式化读取的时候都不到内容
转换流
编码表
gbk编码表:系统常用的
一个汉字:占2个字节
utf8编码表:国际编程人员通用的
一个汉字:占3个字节
转换流
概述
-
为了让IO流和实际文件的编码一致,需要转换流进行转换。
-
转换流本身是字符流的子类
-
可以完成字节流和字符流之间的相互转换
分类
输出转换流:OutputStreamWriter
输入转换流:InputStreamReader
OutputStreamWriter:
原理
- 字符流读出数据
- 把数据按照指定编码集转换为对应的字节
- 把字节通过字节输入流传入目标文件
构造方法
OutputStreamWriter(OutputStream os, String charSetName):
创建一个指定编码集以及转换后的字节输出流的转换流对象
InputStreamReader
原理
- 使用指定的字节输入流读取目标文件的字节
- 根据指定编码集转换为对应的字符
- 转换流对象把字符读入到内存中
构造方法
InputStreamReader(InputStream is, String charSetName):
创建一个指定编码集的输入转换流对象
多线程
相关概念
程序
是一组逻辑和相关数据的集合体,以文件的形式存在与固定的磁盘文件下,一般是静态的资源。
进程
正在运行的程序就是进程,一般情况下进程可以统一的规划使用分配程序中数据。
线程
是进程的组成单位,一个进程使用多个线程的独立执行相互结果得到的效果就是进程的效果
并行
同一个时间点多件事情同时发生互不干扰
并发
同一个时间段多件事情交替执行的现象
CPU调度机制
分时调度:有计划有安排的进行程序的执行
抢占式调度:字面意思,java虚拟机多数是抢占式调度,多线程执行遵守的就是抢占式调度
多线程的实现方式
继承Thread类
概述
Thread类是描述线程相关属性和行为的一个类,定义的线程的共性属性和行为
步骤
- 创建类继承Thread
- 重写run方法,方法中写要进行的操作
- 创建线程类的对象
- 调用start()方法开启线程
实现Runnable接口
概述
Runnable接口是一个具有run方法的接口,本身和线程没有任何关系,但是我们可以把线程要做的事情单独的写在接口的实现类的run方法中,把实现类对象传给线程对象和线程产生了关系,实现任务和线程的分离,降低了任务和线程的关系,降低了耦合性利于编程。
常把Runnable实现类对象叫做线程任务对象
步骤
-
创建类实现Runnable接口
-
重写run方法
-
创建线程任务对象,并传入线程对象中
-
开启线程
匿名内部类的实现方式
示例
// 想开启新的线程但是又不想定义实现类或子类
// 继承方式 匿名内部类实现
new Thread() {
@Override
public void run() {
System.out.println("这是继承的匿名内部类实现");
}
}.start();
// Runnable接口实现
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是接口实现的任务");
}
}).start();
继承Thread和实现Runnable接口的区别
- 继承方式run方法和线程对象结合在一起,线程对象就只能执行一种线程任务,耦合性比较高
- 接口实现方式,线程任务单独定义和线程对象是分开的,任务可以有选择性的分配给线程对象,降低了耦合
run方法和start方法
- run方法是定义线程任务的一个方法,并不能开启线程,仅仅是一个方法,线程在开启的时候会自动运行run方法
- start开启线程,一个线程对象只能调用一次,
Thread常用方法
构造
Thread():
创建一个没有人为定义任务和线程名称的线程对象
Thread(String name):
创建一个没有人为定义任务有线程名称的线程对象
Thread(Runnable r):
创建一个有人为定义任务没有线程名称的线程对象
Thread(Runnable r,String name):
创建一个有人为定义任务有线程名称的线程对象
常用方法
getName():
获取调用线程对象的线程名称
如果人为定义了:获取的就是定义的名称
没有定义:获取的是默认的名称:Thread-x 【x是一个数字 从0开始随着
对象的创建数字依次加1】
setName(String name):
修改调用线程对象的线程名称
setDaemon(boolean b):
是否设置线程为守护线程
守护线程:
他是用来守护执行线程的线程,主要给执行线程提供执行的环境的相关功能资源
如果执行线程都已经消失,守护线程就没有存在的必要
参数:
true :设置为守护线程
false :接触守护线程
isDaemon():判断线程是不是守护线程
true:是守护线程
false:不是守护线程
静态方法
currentThread():
获取当前位置线程的线程的对象
sleep(long s):
线程休眠功能【可以休眠指定的毫秒值】
线程优先级
概念
优先级高的线程先运行(在前面的时间段内,高优先级的线程会运行的多一些),优先级低的线程后运行(在后面的时间段内低优先级的线程运行多一些)
方法
setPriority(int p):
通过给定优先级数字设定优先级,数字越大,优先级越高
数字范围:最小 1,自大的是 10,默认状态就是 5
优先级常量
MAX_PRIORITY 值为 10
NORM_PRIORITY 值是 5
MIN_PRIORITY 值为 1
多线程的安全问题
概念:
多个线程运行过程中操作的是同一个资源,在运行过程中会出现数据交叉的问题
解决方式
- 同步代码块 同步方法
- 使用Lock类的功能(unlock方法和lock方法)方式有缺陷,解决特殊的安全问题
同步代码块
语法格式
synchronized (锁对象) {
有可能发生线程安全的代码
}
锁对象
- 引用数据类型的对象
- 没有确定之前可以是任意的引用对象
- 一点确定对象要保证唯一,即保证锁的唯一
原理
线程抢锁对象,抢到就执行,没抢到就等待
同步方法
语法格式
修饰符 synchronized 返回值类型 方法名(参数列表){
有问题的代码}
锁对象
普通同步方法:
this 【当前调用对象】 调用方法时如果调用对象不一样会出现不一样的锁,就无法保证锁的唯一,还是会出错
静态同步方法
所在类的字节码对象【反射对象】:类名.class
Lock接口
lock():获取锁
unlock():释放锁
线程安全类性总结
1、线程不安全类型:
StringBuilder、ArrayList、HashMap
2、线程安全类型:
StringBuffer、Vector、Hashtable
HashMap支持null键和null值
HashTable不支持null键和null值
线程的生命周期
概述
一条线程从生到死的过程就叫做生命周期。
状态
新建状态:刚刚创建出来
就绪状态:调用了start方法开启线程但是还没有获取cpu
运行状态:开启后获取到cpu正常运行
阻塞状态:运行过程发生异常到线程暂时的放弃CPU的执行权
死亡状态:线程正常死亡会发生异常程序停止
状态对应枚举项
1、NEW:表示新建状态
2、RUNNABLE:表示就绪和运行状态
3、BLOCKED:其他阻塞【调用sleep方法 I/O请求等】
4、WAITING:无限等待【同步阻塞 锁对象调用wait方法】
5、TIMED_WAITING:计时等待【同步阻塞 锁对象调用wait方法】
6、TERMINATED:死亡态
方法
getState():获取线程的状态枚举项
状态转换图
线程池
概述
减少创建和回收线程对象的时间,在没有任务的时候,创建好线程对象储存到一个容器中,任务来的时候直接获取,结束直接还给容器。
好处
-
降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
-
提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
-
提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而导致服务器累死机。
工具类
Executors具有获取线程池对象的方法
方法
newSingleThreadExecutor()
获取一个只有一个线程对象的线程池对象
newFixedThreadPool(int num)
获取一个指定个数线程对象的线程池对象
步骤
1、通过工具类Executors获取线程池对象
2、准备线程任务对象【实现Runnable接口】
3、把线程任务对象提交给线程池对象
使用线程池的方法:submit(Runnable r)
4、关闭线程池【实际开发不需要关】
1、shutdown():把提交的所有的任务执行完关闭线程池
2、shutdownNow():把提交的正在运行的执行完毕关闭线程池
JDK8接口新特性
概述
在具有抽象方法的基础上增加了默认方法和静态方法
默认方法
概述
- 被关键字 default 修饰的普通方法就是默认方法
- 是接口独有的方法
- 只能被接口的实现类使用
使用规则
1、直接被实现类对象调用
2、被实现类重写,之后被实现类对象调用【默认方法可以被重写也可以不被重写】
3、实现类的方法中想要调用接口的默认方法:
1、直接使用实现类对象调用【前提实现类没有重写默认方法】
2、接口名.super.默认方法名(参数)
影响:
1、接口的功能越来越靠近抽象类的功能
2、接口可以被类实现,还是多实现,抽象类只能被继承一个类只能继承一个,接
口的功能的扩展性比抽象类强
3、未来接口有逐步取代抽象类的趋势【未来的技术的使用中接口越来越多】
静态方法
概述:
接口的静态方法属于接口,不能被实现类继承重写,所以实现类对象不能访问静态方法
静态方法是接口独有的,只能使用接口名来访问。
使用:
1、不同的接口可以有相同方法声明的静态方法【不同接口有一模一样静态方法】
2、必须使用接口名访问
Lambda表达式
概述:
Lambda表达式本身是一个函数式,Lambda表达式本质是一个数据,在java中代表的是一个接口的实现类对象,具有实现类对象的相关功能
Lambda的表达式是对部分匿名内部类格式进一步优化得到的一个函数式。
前提:
1、有且只有一个抽象方法的接口才可以使用Lambda表达式
2、要有上下文推断
好处:
1、格式简单好用
2、减少了编译的过程【匿名内部类编译的时候会单独编译为一个字节码文件,Lambda表达式不需要编译成单独的字节码文件】提升代码的运行效率
语法格式:
(参数列表)->{做事的逻辑}
格式解释:
(参数列表):接口抽象方法的参数列表
-> :就是Lambda表达式的标记
{做事的逻辑}:重写的方法的方法体
省略规则:
分为
小括号的省略:
1、参数的数据类型可以省略
2、如果参数有且只有一个参数,小括号也可以省略
花括号的省略:
有且只有一句执行语句的时候可以同时省略花括号 分号 以及 return
【要么都省略要么一个都不要省略】
函数式接口
概述:
有且只有一个抽象方法的接口就是函数式接口。(lambda表达式的使用前提,可以有其他的默认方法)
注解
@FunctionalInterface //加上注释的时候编译会判断是否是函数式接口,不是会报错
理解
使用抽象方法来实现函数式要做的事,函数式接口作为函数式的抽象方法的承载体。
内置的函数式接口
消费性接口:[Consumer]
accept(T t):
- 使用该方法可以消费给定的数据【如何消费数据需要实现类重写】
- 使用在我有一个资源想用有不知道怎么用的时候找Consumer接口
- 函数式接口本身就是函数式的填写,所以他的使用往往就是当做数据进行传输
代码实例
public static void main(String[] args) {
int money = 10000;
// 创建Consumer接口的实现类对象
Consumer< Integer> consumer = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
// 帮忙花钱
System.out.println("小弟不要急不要慌大哥带你飞,拿你的" + money
+ "带你去男人都想去的地方" );
}
};
useMoney(money, consumer);
Consumer< Integer> consumer1 = (Integer t) -> {
// 帮忙花钱
System.out.println("小弟不要急不要慌大哥带你飞,拿你的" + money
+ "带你去优就业学习java必须的飞起来" );
};
useMoney(money, consumer1);
}
private static void useMoney(int money,Consumer<Integer> consumer) {
// 花钱
consumer.accept(money);
}
供给型接口[Supplier]
T get();
功能:通过这个接口可以得到想要的任意数
想要得到一个数据又不知道怎么去得到的时候找Supplier接口
代码实例
private static String getString(Supplier<String> supplier) {
// 接口Supplier帮忙获取字符串
String s = supplier.get();
return s;
}
public static void main(String[] args) {
// 方法中需要Supplier接口的对象 创建他的实现类对象
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "金莲有想法,大朗喝了药";
}
};
Supplier<String> supplier1 = ()->{return "金莲有想法";};
String s = getString(supplier);
System.out.println(s);
String s1 = getString(supplier1);
System.out.println(s1);
String s2 = getString(()->{return "大朗喝了药";});
System.out.println(s2);
}
转换型接口
方法
R apply(T t):
是一个抽象方法
把指定的数据转变为想要的一个数据
andThen(Function f):
是一个默认方法,链接两个Function对象的转换规则进行两次转换
【调用的Function对象先转换然后参数Function对
象执行】
注意事项:
函数式接口的默认方法和抽象方法使用链式编程调用的时候默认方法必须在抽象方法的前面调用
代码实例
// 我有一个资源想转换为另外一个资源不知道怎么转找Function接口来转换
private static <T , R> R exchange(T t,Function<T, R> function) {
// 开始转换数据t
R r = function.apply(t);
return r;
}
private static <T,R,M> M exchange(T t,Function<T, R> function,Function<R, M> function1) {
// 开始转换数据t
// R r = function.apply(t);
// M m = function1.apply(r);
// 是上面两行代码的合并效果
M m = function.andThen(function1).apply(t);
return m;
}
public static void main(String[] args) {
// 准备Function接口的实现类【可以是匿名内部类 也可以lambda表达式】
Function<String, Character[]> function = (t)->{
// 要进行转换的逻辑代码
char[] cs = t.toCharArray();
// 数组不支持向上转型【强制转换】
//Character[] css = (Character) cs;
Character[] css = new Character[cs.length];
int i = 0;
for (char ch : cs) {
css[i++] = ch;
}
return css;
};
Character[] ch = exchange("金莲想法,大郎遭了殃", function);
System.out.println(Arrays.toString(ch));
Function<Character[],List<Character>> function1 = (t)->{
// t 就是要转换的数据 Character[]
ArrayList<Character> list = new ArrayList<Character>();
for (Character ch1 : t) {
list.add(ch1);
}
return list;
};
// 调用方法验证
List<Character> list = exchange("abcd", function, function1);
System.out.println(list);
}
断言型接口
方法
boolean test(T t):
是一个抽象方法,使用一定的判断规则对给定的资源进行判断是否符合判断规则
规则需要在实现类中去重写【重写test方法的时候指定】
Predicate and (Predicate p):
把两个断言型接口的判断规则判断的结果进行逻辑且【与】的处理
Predicate or (Predicate p):
把两个断言型接口的判断规则判断的结果进行逻辑或的处理
Predicate negate():
取判断结果的反向结果
代码实例
public static void main(String[] args) {
// 方法isString要使用到Predicate接口 创建 他的实现类对象
Predicate<String> p = (s)->{
// 重写抽象方法【要指定判断的规则】
boolean b = s.startsWith("ab");
return b;
};
String s = "abcdmks";
boolean b = isString(s, p);
System.out.println(b);// true
// 默认方法的使用
boolean c = p.negate().test("abcd");
System.out.println(c);// false
Predicate<String> p2 = (s1)->{
// 重写抽象方法【要指定判断的规则】
boolean b1 = s1.contains("d");
return b1;
};
boolean d = p.and(p2).test("abmn");
System.out.println(d);// false
boolean e = p.or(p2).test("abmn");
System.out.println(e);// e
}
// 我有一个资源想要判断,但是不知道该怎么去判断找Predicate接口
private static boolean isString(String s,Predicate<String> p) {
// 开始判断这个资源
boolean b = p.test(s);
return b;
}
总结
函数式接口的使用:
1、创建他的实现类对象 【一般使用lambda表达式来体现】
2、抽象方法是用来做事情的
【怎么做的代码需要在lambda表达式的花括号里面重写】
3、函数式接口使用链式编程调用方法的时候默认方法必须在抽象方法的前面
方法引用
概述:
对特殊的lambda表达式进一步变形得到的一个表示接口对象的方式。lambda表达式要重写的方法及方法内容已经在另一个类中有方法实现。
格式
静态方法引用:
类名 :: 方法名
普通方法引用:
对象名 :: 方法名
构造方法引用:
类名 :: new
前提
- 函数式接口
- 上下文推断
测试类
public static void main(String[] args) {
// 使用接口的对象
// 方式一:匿名内部类
InterfaceA aa = new InterfaceA() {
@Override
public void show(int a) {
System.out.println(a);
}
};
// 方式二: Lambda表达式
InterfaceA aa1 = (int a) -> {
System.out.println(a);
};
// 方式三:方法引用
InterfaceA aa2 = new DemoMethod() :: print;
// 接口B 对象创建
// 方式一 匿名内部类
InterfaceB b = new InterfaceB() {
@Override
public void work() {
int i = 100;
System.out.println(i);
}
};
// 方式二 :Lambda表达式
InterfaceB b1 = () -> {
int i = 100;
System.out.println(i);
};
// 方式三 :方法引用
InterfaceB b2 = DemoMethod :: show;
// 使用接口C获取DemoMethod的对象
// 方式一 : 匿名内部类方式
InterfaceC c = new InterfaceC() {
@Override
public DemoMethod get(int a) {
// 获取到对象并返回
return new DemoMethod();
}
};
DemoMethod demo = c.get(100);
System.out.println(demo);
// 方式二:Lambda表达式
InterfaceC c1 = (a)-> {
// 获取到对象并返回
return new DemoMethod(a);
};
DemoMethod demo1 = c1.get(200);
System.out.println(demo1);
// 方式三:方法引用
InterfaceC c2 = DemoMethod :: new ;
DemoMethod demo2 = c2.get(300);
System.out.println(demo2);
Streaming API
概述:
Stream是一个用来对容器进行过滤转换等操作的数据接口,定义了相关的操作方法可以连续的对集合的数据进行操作,提高了操作数据的效率。
注意
每调用一次功能,Stream对象发生一次变换,同时旧的Stream对象消失,变得无法操作,同时产生新的Stream对象
使用
Steam对象的获取:
- Collection的Stream获取
使用集合对象调用方法 stream()
- Map的Stream的获取
不能直接获取Stream流对象 只能转换为单列集合获取Stream对象
KeySet():获取Map集合所有的key的set集合
entrySet():获取所有entry对象的set集合
values():获取所有的value值的Collection集合
- 数组的Stream获取:
使用Stream的静态方法of获取对应的Stream对象
Stream.of(数组名)
功能
一个功能相当于一个工序
Stream filter(Predicate p):
根据指定的规则进行数据过滤【筛选】符合规则的数据保留 不符合的数据淘汰】
Stream limit(int num):
只获取头num个的元素
Stream skip(int num):
跳过开头的num个数元素
Stream map(Function f):
映射:把要操作的元素按照指定的转换方式转为另一个类型的数据
Stream concat(Stream s1,Stream s2):
静态方法:
拼接两个Stream流为一个新的Stream流
toArray():收集Stream流中的数据到数组中
【把Stream流变为数组】
collect(Collector c):
Collector :Collectors.toList()
Collector :Collectors.toSet()
收集Stream流中的数据到集合
【把Stream变为集合】
forEach(Consumer c):
遍历Stream中的数据
【经常用来输出】
int count():
获取Stream中要操作的数据的个数
代码实例
public static void main(String[] args) {
String[] arr = {"乃亮","宝宝","大郎","羽凡","PGone","喆喆","庆庆"};
// 获取Stream对象
Stream<String> stream = Stream.of(arr);
// 调用功能
//long l = stream.count();
//System.out.println(l);
// 同一个Stream对象调用了一次方法 他就消失了不能二次使用
Stream<String> stream2 = stream.filter((s)->{return s.length() == 2;});
//System.out.println(stream2);// Stream流没有承载数据的能力
//stream2.forEach((s)->{System.out.println(s);});
// stream2.forEach(System.out :: println);
Stream<String> stream3 = stream2.limit(4);
//stream3.forEach(System.out :: println);
Stream<String> stream4 = stream3.skip(1);
// stream4.forEach(System.out :: println);
Stream<String> stream5 = stream4.map((s)->{return s += 123;});
// stream5.forEach(System.out :: println);
Stream<ArrayList<String>> stream6 = stream5.map((s)->{
ArrayList<String> list = new ArrayList<String>();
list.add(s);
return list;});
// stream6.forEach(System.out :: println);
Stream<String> stream7 = Stream.of("jinlian");
Stream<Serializable> stream8 = Stream.concat(stream6, stream7);
//stream8.forEach(System.out :: println);
// 收取数据到数组中
// Object[] array = stream8.toArray();
// System.out.println(Arrays.toString(array));
// 把数据收集到集合
List<Serializable> list = stream8.collect(Collectors.toList());
System.out.println(list);
}
终结方法和延迟方法
返回值类型还是Stream类型的方法就是延迟方法
filter limit skip map concat
返回值不是Stream类型是其他的数据类型是终结方法
count toArray collect forEach
练习
有两个 Arraylist 集合,存储队伍中的多个成员姓名,使用 Stream 方式,对以下步骤进行操作
1、第一个队伍只要名字为 3 个字的成员姓名
2、第一个队伍只要筛选之后的前三个人
3、第二个队伍只要姓张的
4、第二个队伍筛选之后不要前两个人
5、将两个队伍合并成一个队伍
6、合并之后的队伍中的所有人名字变为Person(自定义类型)对象,并将对象存
储到一个ArrayList 集合中
队伍 1:宫本武藏、宋公明、苏有朋、石头人、时传祥、李耳、庄子、洪七公
队伍 2:帕瓦罗蒂、张三疯、赵薇薇、张自忠、孛儿只斤铁木真、张天爱、张翠花
代码示例:
package com.ujiuye.demo;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamText {
public static void main(String[] args) {
// 创建两个ArrayList的集合对象
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
String[] arr1 = "宫本武藏、宋公明、苏有朋、石头人、时传祥、李耳、庄子、洪七公".split("、");
String[] arr2 = "帕瓦罗蒂、张三疯、赵薇薇、张自忠、孛儿只斤铁木真、张天爱、张翠花".split("、");
for (String name : arr2) {
list2.add(name);
}
for (String name : arr1) {
list1.add(name);
}
// 获取集合的Stream对象
Stream<String> stream1 = list1.stream();
Stream<String> stream2 = list2.stream();
// 按需办事
// 第一个队伍只要名字为 3 个字的成员姓名
// 第一个队伍只要筛选之后的前三个人
Stream<String> stream11 = stream1.filter((s)->{return s.length() == 3;}).limit(3);
// 第二个队伍只要姓张的
// 第二个队伍筛选之后不要前两个人
Stream<String> stream21 = stream2.filter((name)->{return name.startsWith("张");}).skip(2);
// "张"没有上下文推断 在引用的时候不能引用到正确的方法
// Stream<String> stream21 = stream2.filter(new String() :: startsWith).skip(2);
// 两个队伍合并成一个队伍
Stream<String> stream = Stream.concat(stream11, stream21);
// 合并之后的队伍中的所有人名字变为Person(自定义类型)对象,
// lambda表达式
// Stream<Person> map_stream = stream.map((name)->{return new Person(name);});
// 方法引用
Stream<Person> map_stream = stream.map(Person :: new);
// 并将对象存到一个ArrayList 集合中
List<Person> list = map_stream.collect(Collectors.toList());
ArrayList<Person> list3 = new ArrayList<Person>();
for (Person person : list) {
list3.add(person);
}
System.out.println(list3);
}
}