Java基础(List、Set、Map、File、IO)

集合

1. List

1.1. ArrayList(常用)

内部基于数组实现的一个集合类。查询比较快,添加和删除相对比较慢;

不是同步的(存在线程安全问题);

遍历方式:

ArrayList bag = new ArrayList();

for(int i=0;i<bag.size();i++){
   System.out.println(bag.get(i));
}

for (ArrayList ele : bag){
  System.out.println(ele);
}

//使用迭代器遍历集合ArrayList   bag获得一个迭代器
// 获得双向的迭代器
Iterator it = bag.iterator();

while(it.hasNext()){
	 System.out.println(it.next());
}

while(iterator.hasPrevious()){
	System.out.println(iterator.previous());
}
1.2. LinkedList

1、 内部是基于链表结构实现的。添加和删除比较快,查询相对ArrayList比较慢

2、 内部相对于ArrayList而言多了一些操作头和尾的方法

3、 可以充当队列,堆栈

4、 不是线程安全的(同步的)

这种一般记住一些常用的,然后可以去查看API

2. Set

2.1. HashSet(任意类型)

1.不能够添加重复元素 hashCode 和 equals()

2.无序(不保证和添加和打印顺序一致)

3.添加任意类型

2.2. TreeSet(同类型)

1.无序:不保证(不记录)我们的添加顺序;

2.不重复:不能够添加重复元素

3.感觉内部存储有一定的顺序

4.不能存在不同的数据类型

注意:TreeSet一旦添加了第一个元素后就不能添加其它数据类型的元素了,只能添加相同数据类型的元素,除非将容器中所有的元素全部清空,才能添加新的数据类型的元素

虽然说TreeSet没有顺序,但其实内部还是有顺序的

1.TreeSet内部 是按照大小进行排序的,大小有对象与对象之间比较进行决定的

2.设计TreeSet之前:Java设计了一个接口Comparable接口,其中提供了对象之间比较的方法CompareTo

3.TreeSet会调用对象的CompareTo方法,比较对象,所以我们放入的对象需实现Comparable

如果采用的是自然排序调用对象的compareTo方法,如果返回0 表示相等;

大于且返回正数,升序排列 。大于且返回负数,降序排列 (测试得出结论)

3. Map

3.1. 基本结构

Map 接口
|-- TreeMap : 判断重复的规则和TreeSet一样
TreeMap中的键(key)要么是具有自然排序能力;或者TreeMap中提供一个比较器
如果key是自然或者定制排序,返回值是0表示,key是重复的,如果是正数,则按照key的升序排序,否则是降序

|-- HashMap : key判断键是否重复和HashSet判断重复一样: 1. hashCode 2.equals()

|-- HashTable : 就是一个线程安全的HashMap

|-- LinkedHashMap: 就是一个内部维护了一个链表的HashMap,可以保证存入和取出顺序

|-- Properties:特殊的HashTable,只不过key-value都是String类型,一般用来做
配置文件

3.2. 方法

1、 Collection values() 返回一个Map中的所有的value值 Collection集合

2、 Set keySet() 返回所有的key值的集合**(key是唯一的,所以返回的是Set集合)**

3、 Set entrySet() 返回所有的entry对象**(key是唯一的,所以返回的是Set集合)**

3.2.1 拿出数据

失败的方法

1、foreach 失败!

原因:Map和Iterable没有任何关系

2、普通for/ while / do-while 失败!

原因: Map中没有通过索引来获得数据的方法

正确的方法:

1、遍历方式一:get(Object key)

Map m = new HashMap();
Set keys = m.keySet(); // 先获得所有的key -> set
for (Object k : keys) {
	System.out.println(k+"<---->"+m.get(k)); // 通过调用Object get(Object key) 获得对应的value
}

2、遍历方式二:entrySet()

Map m = new HashMap();
Set entrys = m.entrySet(); // 通过entrySet方法得到全部的Entry对象
for (Object en : entrys) {
	// 需要把en强制转成 Entry类型
	Entry e = (Entry)en;
	System.out.println(e.getKey()+"--"+e.getValue());  // 遍历集合,依次取出数据
}
3.3. Map特点及使用场景选择

Key 唯一且无序【不保证添加顺序和打印顺序一致】

1.HashMap中k的值没有顺序,常用来做统计。 根据hashCode保存,jdk1.8以后hashMap源码 变了,底层优化了

img

表示当相同hash值相同的元素大于8个时候,存储结构会变成红黑树来存储,而之前是链表结构

2.LinkedHashMap它内部维护了一个链表,保持Key插入的顺序。迭代的时候,也是按照插入顺序迭代。

3.TreeMap的顺序是Key的自然顺序(如整数从小到大,默认是按键值的升序排序),也可以指定比较函数。Comparator

4.HashtableHashMap类似,不同的是:它不允许记录的键或者值为null;它支持线程的同步、即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。

注意:LinkedHashMap在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会 比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和值无关,而HashMap的遍历速度和他的容量有关

3.4. Map使用的选择

1、Map中,HashMap具有超高的访问速度,如果我们只是在Map 中插入、删除和定位元素,而无关线程安全或者同步问题,HashMap 是最好的选择。

2、如果考虑线程安全或者写入速度的话,可以使用HashTable,JDK8后建议使用ConcurrentHashMap替代HashTable,既能获取超高的访问速度,又能保证线程安全

3、如果想按怎么存的顺序怎么取,比如队列形式,排队,那么使用LinkedHashMap

4、如果需要让Map按照key进行升序或者降序排序,那就用TreeMap

3.5. Properties
3.5.1 特点

1、表示了一个持久的属性集

2、放入Properties中的key-value都是String

3、Properties中提供了特殊的存值和取值的方法,尽量不要用Map的方法

4、void list(PrintStream out) 简单理解: 此方法可以把Properties中的数据写入磁盘文件

5、void load(InputStream inStream) 简单理解: 可以把磁盘文件中的数据读取到Properties中

3.5.2 使用
Properties properties = new Properties();
properties.setProperty("username", "xw");
properties.setProperty("password", "123456");
PrintStream ps = new PrintStream("F:/user.txt");
properties.list(ps);  // 写入磁盘文件

//-------------------------------------------//

FileInputStream fis = new FileInputStream("F:/user.txt")
properties.load(fis);  // 读取到properties里面
		
String property = properties.getProperty("username");
System.out.println(property);
3.6. Collections工具类

使用方法:

ArrayList list  = new ArrayList();
// 所有的数据填充到集合
Collections.addAll(list,1,2,3,4,5);
3.7. 示例:统计字符串中每个字符出现的次数

用Map来实现

void strCount() {
  String str = "aabbbcccc";
  Map<Character, Integer> map = new HashMap<>();
  for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);  // 取出每一个字符
    if(map.containsKey(c)){  // 如果已经存在就+1
      map.put(c,map.get(c)+1);
    }else {
      map.put(c,1);  // 如果之前不存在就设置出现了一次
    }
  }
  System.out.println(map);
  // 格式不对,用entrySet取出来格式化一下
  Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
  for (Map.Entry<Character, Integer> entry : entrySet) {    System.out.println(entry.getKey()+"="+entry.getValue());
  }
}

4. 文件File

4.1. 基本方法

创建对象:File(String pathname)

创建文件夹:mkdir(),如果路径不存在则异常,用 **mkdirs()**可以生成不存在的路径

创建文件:createNewFile()

isDirectory() 判断是否是一个目录
isFile() 判断是否是一个文件
exists() 测试此抽象路径名表示的文件或目录是否存在

list的一系列方法

File[] listRoots() 列出可用的文件系统根(操作系统上面的盘符)

eg:C:\ D:\ E:\

String[] list() 返回当前的文件夹对象下面一层的所有的文件(文件夹)的名字

eg:文件夹1 文件夹2 a.txt b.txt

File[] listFiles() 返回当前的文件夹对象下面一层的所有的文件(文件夹)(File对象的形式

eg:C:\文件夹1 C:\文件夹2 C:\a.txt C:\b.txt

4.2. 过滤器

自己写一个MyFilter实现类库的FilenameFilter接口,重写一个accept方法,书写自定义的过滤规则。

在调用list的时候传入实例化的MyFilter对象,之后返回的list就是一个符合规则的。

需要理解一下源码具体是怎么实现的:

image-20220606151657378

5. IO流

5.1. 字节流

字节输入流:FileInputStream

主要是read()方法,没有参数的一次读取一个数据字节(不常用),有参数的可以自定义(中文会乱码,因为中文是两个字节表示的)

FileInputStream fis = new FileInputStream("cc.txt");
int len;//读取的字节的个数
byte[] arr = new byte[1024];//五个字节的数据,缓存在该数组的
while( (len = fis.read(arr)) !=  -1 ){
  // 字节数组转为字符串(解码)
	System.out.println(new String(arr,0,len) );
}
fis.close();

字节输出流:FileOutputStream

主要是write()方法,用完之后记得close()关闭流资源

// 创建一个字节输出流
FileOutputStream fos = new FileOutputStream("output.txt",true); // true表示追加append
// 调用方法,字符串转为字节数组(编码)
byte[] bytes = "abcde".getBytes();
fos.write(bytes);
fos.close();

拷贝一个图片

// 源文件
FileInputStream fis = new FileInputStream("source.jpg");
// 拷贝之后的文件
FileOutputStream fos = new FileOutputStream("D:/copy.jpg");
// 边读边写
byte[] bytes = byte[1024]; 
int len;  // 记录每次读取的个数

while( (len = fis.read(bytes)) != -1){
  fos.write(bytes,0,len);
}
// 先开后关
fos.close();
fis.close();
5.2. 字符流

文件输入流:FileReader

与字节不同的是这里是char[] 字节是byte[]

FileReader reader = new FileReader("D:/123.txt");
char[] cbuf = new char[3];
int len;
while( (len = reader.read(cbuf)) != -1 ){
  System.out.println(new String(cbuf,0,len));
}
reader.close();

文件输出流:FileWriter

一个缓冲,需要刷新才能存数据进去

FileWriter writer = new FileWriter("write.txt");
writer.write("我是刚才写入磁盘的字符");
// 在此之前这样数据是存不进去的,需要刷新
write.flush();
write.close(); // 其实在关闭流的同时也刷新了的
5.3. 字节流和字符流的区别

1、操作的单位不一样,一个是字节byte,一个是字符char

2、操作中文的时候使用字符流更方便,字节流更广泛:文本、视频、音频、图片…

3、字符流中有可以直接写字符串的方法

4、字节输出流 : 程序 —> 磁盘文件 如果不关闭流也会写入
字符输出流 : 程序—>缓冲区—> 磁盘文件 如果不关闭流或者刷新缓冲区,不会写入文件
·字符输出流,关闭的时候会先刷新
·关闭之后不能够再操作;
·刷新之后可以继续操作;
什么时候会用到刷新 : 写入的数据比较多,可以在中途手动调用刷新的方法提交数据

5.4. 转换流

当别人的接口需要的参数是字节流,而我们要操作的是字符流(有中文),就需要在方法体中将字节流转字符流。

字节流转为字符流

在创建此类的对象时候,构造方法中的数据来源是一个InputStream(字节输入流)

eg:输入的

FileInputStream fis = new FileInputStream("D:/a.txt");
// 传入字节输入流对象
InputStreamReader reader = new InputStreamReader(fis);
// 读字符流
char[] cbuf = new char[10];
int  len;
while((len = reader.read(cbuf))!=-1){
  System.out.println(new String(cbuf,0,len));
}
reader.close();

在创建此类的对象时候,构造方法中的数据输出是一个OutputStream(字节输出流)

eg:输出的

FileOutputStream fos = new FileOutputStream("D:/a.txt");
OutputStreamWriter writer = new OutputStreamWriter(fos);
writer.write("测试Hello World");
5.5. 缓冲流

空间换时间【效率】

FileInputStream fis = new FileInputStream("D:/a.txt");
// 转化为缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bytes = new byte[1024];
int len;
while( (len = bis.read(bytes)) !=-1){
  System.out.println(new String(bytes,0,len));
}
bis.close();
fis.cloes();

注意:如果数据量比较大用这个缓冲流比较好,但是如果数据量比较小,用缓冲流反而会比较慢 (例子:搬家打包衣服,如果衣服多,打包的多,就用缓冲流,如果只有一件衣服,一件也打包,就太麻烦了)

5.6. IO异常处理

针对上面那个拷贝图片的示例,如果值抛出异常而不处理,是不行的。

image-20220606184812065

我们需要用try catch来解决,在catch中接收异常然后提示错误信息

最后一定都需要在finally中关闭流。

注意jdk特性

//自动关闭的流资源,必须是实现了AutoCloseable
try(需要自动关闭的流资源){
可能发生异常的代码块
}catch(){
捕获异常之后要做的处理
}
try(
	FileInputStream fis = new FileInputStream(src);
	FileOutputStream fos = new FileOutputStream(dest);
){
	byte[] b = new byte[1024];
	int len;
	while((len = fis.read(b)) != -1){
		fos.write(b,0,len);
	}
}catch(Exception e){
	e.printStackTrace();
}

6. TCP、UDP

URL(Uniform Resource Locator)是统一资源定位符,俗称请求网址。

URI(Uniform Resource Identifier) 是统一资源标识符,俗称请求资源路径。

http://localhost:8080/myweb/hello.html以上web地址

加粗部分+非加粗部分=URL。 非加粗部分=URI;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值