方法引用是为了进一步简化Lambda表达式的写法。
方法引用的格式:类型或者对象::引用的方法。
方法引用有四种形式:
ist<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
lists.forEach( s -> System.out.println(s));
// 方法引用!
lists.forEach(System.out::println);
引用格式:类名::静态方法
简化步骤:定义一个静态方法,把需要简化的代码放到一个静态方法中去。
静态方法引用的注意事项:被引用的方法的参数列表要和函数式接口中的抽象方法的参数列表一致
Student
public class Student {
private String name ;
private int age ;
private char sex ;
public static int compareByAge(Student o1 , Student o2){
return o1.getAge() - o2.getAge();
}
// ...
}
排序
List<Student> lists = new ArrayList<>();
Student s1 = new Student("李铭",18,'男');
Student s2 = new Student("冯龙",23,'男');
Student s3 = new Student("王乐乐",21,'男');
Collections.addAll(lists , s1 , s2 , s3);
Collections.sort(lists, ( o1, o2) -> Student.compareByAge(o1 , o2));
// 如果前后参数是一样的,而且方法是静态方法,既可以使用静态方法引用
Collections.sort(lists, Student::compareByAge);
格式: 对象::实例方法
简化步骤:定义一个实例方法,把需要的代码放到实例方法中去。
实例方法引用的注意事项:被引用的方法的参数列表要和函数式接口中的抽象方法的参数列表一致
List<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
// 对象是 System.out = new PrintStream();
// 实例方法:println()
// 前后参数正好都是一个
lists.forEach(s -> System.out.println(s));
lists.forEach(System.out::println);
特定类型:String ,任何类型
格式:特定类型::方法
注意:如果第一个参数列表中的形参中的第一个参数作为了后面的方法的调用者,并且其余参数作为后面方法的形参,那么就可以用特定类型方法引用了
String[] strs = new String[]{"James", "AA", "John",
"Patricia","Dlei" , "Robert","Boom", "Cao" ,"black" ,
"Michael", "Linda","cao","after","sBBB"};
// public static void sort(T[] a, Comparator super T> c)
// 需求:按照元素的首字符(忽略大小写)升序排序!!!
Arrays.sort(strs, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareToIgnoreCase(s2);// 按照元素的首字符(忽略大小写)比较。
}
});
Arrays.sort(strs, (String s1, String s2) -> {
return s1.compareToIgnoreCase(s2);// 按照元素的首字符(忽略大小写)比较。
});
Arrays.sort(strs, ( s1, s2 ) -> s1.compareToIgnoreCase(s2));
// 特定类型的方法引用:
Arrays.sort(strs, String::compareToIgnoreCase);
System.out.println(Arrays.toString(strs));
格式是:类名::new
注意点:前后参数一致的情况下,又在创建对象就可以使用构造器引用s -> new Student(s) => Student::new
List<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
// 集合默认只能转成Object类型的数组。
Object[] objs = lists.toArray();
System.out.println("Object类型的数组:"+ Arrays.toString(objs));
// 我们想指定转换成字符串类型的数组!!
// 最新的写法可以结合构造器引用实现 。
// default T[] toArray(IntFunction generator)
String[] strs = lists.toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
String[] strs1 = lists.toArray(s -> new String[s] );
String[] strs2 = lists.toArray(String[]::new);
System.out.println("String类型的数组:"+ Arrays.toString(strs2));
Lambda表达式是JDK1.8开始之后的新技术,是一种代码的新语法,作用是为了简化匿名内部类的代码写法
Lambda表达式的格式
(匿名内部类被重写方法的形参列表) -> {
// 被重写方法的方法代码
}
Lambda表达式的使用前提:
Lambda表达式只能简化函数式接口的匿名内部类写法:
@FunctionalInterface
函数式接口注解:一旦某个接口加上了这个注解,这个接口只能有且仅有一个抽象方法。
这个接口就可以被Lambda表达式简化。
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":执行~~~");
}
});
t.start();
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+":执行~~~");
});
t1.start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+":执行~~~");
}).start();
new Thread(() -> System.out.println(Thread.currentThread().getName()+":执行~~~")).start();
List<Student> lists = new ArrayList<>();
Student s1 = new Student("李铭",18,'男');
Student s2 = new Student("冯龙",23,'男');
Student s3 = new Student("王乐乐",21,'男');
Collections.addAll(lists , s1 , s2 , s3);
// 按照年龄进行升序排序!
Collections.sort(lists, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() - s2.getAge();
}
});
// 简化写法
Collections.sort(lists ,(Student t1, Student t2) -> {
return t1.getAge() - t2.getAge();
});
Collections.sort(lists ,(Student t1, Student t2) -> t1.getAge() - t2.getAge());
// 参数类型可以省略
Collections.sort(lists ,( t1, t2) -> t1.getAge() - t2.getAge());
System.out.println(lists);
Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化)
List<String> names = new ArrayList<>();
names.add("胡伟光");
names.add("甘挺");
names.add("洪磊");
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
names.forEach((String s) -> {
System.out.println(s);
});
names.forEach((s) -> {
System.out.println(s);
});
names.forEach(s -> {
System.out.println(s);
});
names.forEach(s -> System.out.println(s) );
names.forEach(System.out::println);
在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念 ,用于解决已有集合/数组类库有的弊端。
Stream流能解决什么问题:
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.stream().filter(s -> s.startsWith("张")).filter( s -> s.length()== 3 )
.forEach(System.out::println);
Stream流式思想的核心:
default Stream<E> stream();
Collection<String> c = new ArrayList<>();
Stream<String> ss = c.stream();
/** --------------------Map集合获取流------------------------------- */
Map<String, Integer> map = new HashMap<>();
// 先获取键的Stream流。
Stream<String> keyss = map.keySet().stream();
// 在获取值的Stream流
Stream<Integer> valuess = map.values().stream();
// 获取键值对的Stream流(key=value: Map.Entry)
Stream<Map.Entry<String,Integer>> keyAndValues = map.entrySet().stream();
/** ---------------------数组获取流------------------------------ */
// 数组也有Stream流。
String[] arrs = new String[]{"Java", "JavaEE" ,"Spring Boot"};
Stream<String> arrsSS1 = Arrays.stream(arrs);
Stream<String> arrsSS2 = Stream.of(arrs);
forEach
: 逐一处理(遍历)
count
:统计个数
long count();
filter
: 过滤元素
Stream
limit
: 取前几个元素
skip
: 跳过前几个
map
: 加工方法
把原来的元素加工以后,重新放上去
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
concat
: 合并流
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
list.stream().filter( s -> s.length() == 3 ).filter( s -> s.startsWith("张"))
.forEach( System.out::println);
// 统计数量
long count = list.stream().filter( s -> s.length() == 3 )
.filter( s -> s.startsWith("张")).count();
System.out.println(count);
// 取前2个
list.stream().filter(s -> s.length() == 3).limit(2)
.forEach(System.out::println);
// 跳过前2个
list.stream().filter(s -> s.length() == 3).skip(2)
.forEach(System.out::println);
// 把名称加工成学生对象放入list中
list.stream().map(Student::new).forEach(System.out::println);
合并流
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
// 数组流
Stream<Integer> s1 = Stream.of(10, 20 ,30 ,40);
// 集合流
Stream<String> s2 = list.stream();
// 合并流
Stream<Object> s3 = Stream.concat(s1,s2);
s3.forEach(System.out::println);
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
/**
* 1. 第一个队伍只要名字为3个字的成员姓名;
* 2. 第一个队伍筛选之后只要前3个人;
*/
Stream<String> oneStream =
one.stream().filter(s -> s.length() == 3).limit(3);
/**
* 3. 第二个队伍只要姓张的成员姓名;
* 4. 第二个队伍筛选之后不要前2个人;
* 5. 将两个队伍合并为一个队伍;
*/
Stream<String> twoStream =
two.stream().filter(s -> s.startsWith("张")).skip(2);
Stream<String> allStream = Stream.concat(oneStream , twoStream);
/**
* 6. 根据姓名创建`Student`对象; (加工)
* 7. 打印整个队伍的Student对象信息。
*/
//allStream.map(s -> new Student(s)).forEach(System.out::println);
allStream.map(Student::new).forEach(System.out::println);
一旦Stream调用了终结方法,流的操作就全部终结了,不能继续使用,只能创建新的Stream操作。
终结方法: foreach
, count
非终结方法:每次调用完成以后返回一个新的流对象,可以继续使用,支持链式编程!
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
// foreach终结方法
list.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3).forEach(System.out::println);
long count = list.stream().filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3).count();
System.out.println(count);
收集Stream流:把Stream流的数据转回成集合。
Stream的作用是:把集合转换成一根传送带,借用Stream流的强大功能进行的操作。但是实际开发中数据最终的形式还是应该是集合,最终Stream流操作完毕以后还是要转换成集合。这就是收集Stream流。
收集Stream流的含义:就是把Stream流的数据转回到集合中去。
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
Stream<String> zhangLists = list.stream().filter(s -> s.startsWith("张"));
// 把stream流转换成Set集合。
Set<String> sets = zhangLists.collect(Collectors.toSet());
System.out.println(sets);
// 把stream流转换成List集合。
Stream<String> zhangLists1 = list.stream().filter(s -> s.startsWith("张"));
List<String> lists= zhangLists1.collect(Collectors.toList());
System.out.println(lists);
// 把stream流转换成数组。
Stream<String> zhangLists2 = list.stream().filter(s -> s.startsWith("张"));
Object[] arrs = zhangLists2.toArray();
// 可以借用构造器引用申明转换成的数组类型!!!
//String[] arrs1 = zhangLists2.toArray(String[]::new);
File类:代表操作系统的文件对象
File类:是用来操作操作系统的文件对象的,删除文件,获取文件信息,创建文件(文件夹)…
广义来说操作系统认为文件包含(文件和文件夹)
File类的创建文件对象的API:
java.io.File
public File(String pathname)
:根据路径获取文件对象public File(String parent, String child)
:根据父路径和文件名称获取文件对象!File类创建文件对象的格式:
File f = new File("绝对路径/相对路径");
File f = new File("文件对象/文件夹对象");
- 创建文件对象可以用绝对路径也可以用相对路径。
- 相对路径只能用于寻找工程下的文件。
- 文件对象可以表示文件也可以表示文件夹!
File f1 = new File("D:\\itcast\\图片资源\\beautiful.jpg");
System.out.println(f1.length()); // 获取文件的大小,字节大小
// 2.创建文件对象:使用相对路径
File f2 = new File("Day09Demo/src/dlei01.txt");
System.out.println(f2.length());
// 3.创建文件对象:代表文件夹。
File f3 = new File("D:\\itcast\\图片资源");
System.out.println(f3.exists());// 判断路径是否存在!!
public String getAbsolutePath()
:返回此File的绝对路径名字符串。public String getPath()
: 获取创建文件对象的时候用的路径public String getName()
: 返回由此File表示的文件或目录的名称。public long length()
: 返回由此File表示的文件的长度。// 1.绝对路径创建一个文件对象
File f1 = new File("D:/itcast/图片资源/meinv.jpg");
// a.获取它的绝对路径。
System.out.println(f1.getAbsolutePath());
// b.获取文件定义的时候使用的路径。
System.out.println(f1.getPath());
// c.获取文件的名称:带后缀。
System.out.println(f1.getName());
// d.获取文件的大小:字节个数。
System.out.println(f1.length());
System.out.println("------------------------");
// 2.相对路径
File f2 = new File("Day09Demo/src/dlei01.txt");
// a.获取它的绝对路径。
System.out.println(f2.getAbsolutePath());
// b.获取文件定义的时候使用的路径。
System.out.println(f2.getPath());
// c.获取文件的名称:带后缀。
System.out.println(f2.getName());
// d.获取文件的大小:字节个数。
System.out.println(f2.length());
public boolean exists()
:此File表示的文件或目录是否实际存在。public boolean isDirectory()
:此File表示的是否为目录。public boolean isFile()
:此File表示的是否为文件// 1.文件对象。
File f1 = new File("D:\\itcast\\图片资源\\meinv.jpg");
// a.判断文件路径是否存在
System.out.println(f1.exists()); // true
// b.判断文件对象是否是文件,是文件返回true ,反之
System.out.println(f1.isFile()); // true
// c.判断文件对象是否是文件夹,是文件夹返回true ,反之
System.out.println(f1.isDirectory()); // false
// 1.文件对象。
File f2 = new File("D:\\itcast\\图片资源");
// a.判断文件路径是否存在
System.out.println(f2.exists()); // true
// b.判断文件对象是否是文件,是文件返回true ,反之
System.out.println(f2.isFile()); // false
// c.判断文件对象是否是文件夹,是文件夹返回true ,反之
System.out.println(f2.isDirectory()); // true
public boolean createNewFile()
:当且仅当具有该名称的文件尚不存在时,public boolean delete()
:删除由此File表示的文件或目录。 (只能删除空目录)public boolean mkdir()
:创建由此File表示的目录。(只能创建一级目录)public boolean mkdirs()
:可以创建多级目录(建议使用的)File f = new File("Day09Demo/src/dlei02.txt");
// a.创建新文件,创建成功返回true ,反之
System.out.println(f.createNewFile());
// b.删除文件或者空文件夹
System.out.println(f.delete());
// 不能删除非空文件夹,只能删除空文件夹
File f1 = new File("D:/itcast/aaaaa");
System.out.println(f1.delete());
// c.创建一级目录
File f2 = new File("D:/itcast/bbbb");
System.out.println(f2.mkdir());
// d.创建多级目录
File f3 = new File("D:/itcast/e/a/d/ds/fas/fas/fas/fas/fas/fas");
System.out.println(f3.mkdirs());
public String[] list()
public File[] listFiles()
常用File dir = new File("day09/src/com/itheima");
// a.获取当前目录对象下的全部一级文件名称到一个字符串数组返回。
String[] names = dir.list();
for (String name : names) {
System.out.println(name);
}
// b.获取当前目录对象下的全部一级文件对象到一个File类型的数组返回。
File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
}
// ---------拓展------------
File f1 = new File("C:\\Users\\Administrator\\Documents\\codes\\notes\\java-notes\\java补充知识点\\codes\\seniorJava\\day09\\src\\com\\itheima\\_20File目录的遍历\\FileDemo.java");
long time = f1.lastModified(); // 最后修改时间!
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(time));
方法在方法中又调用了自己
- 递归是自己调用自己。
- 递归如果控制的不恰当,会形成递归的死循环,从而导致栈内存溢出错误!!
- 递归应该防止进入递归的死循环!
一个简单的例子,计算
f ( x ) = f ( x − 1 ) + 1 f(x) = f(x-1) + 1 f(x)=f(x−1)+1
public class RecursionDemo02 {
public static void main(String[] args) {
System.out.println(f(10));
}
public static int f(int x){
if(x == 1) {
return 1;
}else{
return f(x - 1) + 1 ;
}
}
}
递归算法分为三个要素:
递归公式
f ( x ) = f ( x ) + 1 f(x)=f(x)+1 f(x)=f(x)+1
递归终结点
f ( 1 ) = 1 f(1)=1 f(1)=1
递归方向
必须走向终结点
必须满足三要素,否则递归会出现死亡
这是一个非规律递归,实现步骤是:
/**
* 去某个目录下搜索某个文件
* @param dir 搜索文件的目录。
* @param fileName 搜索文件的名称。
*/
public static void searchFiles(File dir , String fileName){
// 1.判断是否存在该路径,是否是文件夹
if(dir.exists() && dir.isDirectory()){
// 2.提取当前目录下的全部一级文件对象
File[] files = dir.listFiles(); // null/[]
// 3.判断是否存在一级文件对象(判断是否不为空目录)
if(files!=null && files.length > 0){
// 4.判断一级文件对象
for (File f : files) {
// 5.判断file是文件还是文件夹
if(f.isFile()){
// 6.判断该文件是否为我要找的文件对象
if(f.getName().contains(fileName)){
System.out.println(f.getAbsolutePath());
try {
// 启动它(拓展)
Runtime r = Runtime.getRuntime();
r.exec(f.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}else{
// 7.该文件是文件夹,文件夹要递归进入继续寻找
searchFiles(f ,fileName);
}
}
}
}
}
字符集:各个国家为自己国家的字符取的一套编号规则。计算机的底层是不能直接存储字符的。计算机的底层只能存储二进制。010101二进制就是可以转成10进制的。10进制就是整数编号。101 = 12^0 + 02^1 + 1*2^2 = 5
IO输入输出流:输入/输出流。
引入:
File类只能操作文件对象本身,不能读写文件对象的内容。
读写数据内容,应该使用IO流。
IO流是一个水流模型:IO理解成水管,把数据理解成水流。
IO流的分类
按照流的方向分为:输入流,输出流。
按照流的内容分为: 字节流,字符流。
所以流大体分为四大类:
IO流是读写传输数据的,IO流有很多种,每种流有自己的功能特点。
IO流的体系
字节流 | 字节流 | 字符流 | 字符流 |
---|---|---|---|
字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
InputStream | OutputStream | Reader | Writer(抽象类) |
FileInputStream | FileOutputStream | FileReader | FileWriter(子类实现类) |
FileInputStream文件字节输入流
作用:以内存为基准,把磁盘文件中的数据按照字节的形式读入到内存中的流,简单的来说,就是按照字节读取文件数据到内存
构造器
public FileInputStream(File path)
:创建一个字节输入流管道与源文件对象接通public FileInputStream(String pathName)
:创建一个字节输入流管道与文件路径对接方法
public int read()
每次读取一个直接返回,读取完毕会返回-1
public int read(byte[] buffer)
从字节输入流中读取字节到字节数组中去,返回读取的字节数量,没有字节可读返回-1
- 一个一个字节读取英文和数字没有问题。
- 但是一旦读取中文输出无法避免乱码,因为会截断中文的字节。
- 一个一个字节的读取数据,性能也较差,所以禁止使用此方案!
// 1.创建文件对象定位dlei01.txt
File file = new File("Day09Demo/src/dlei01.txt");
// 2.创建一个字节输入流管道与源文件接通
InputStream is = new FileInputStream(file);
// 3.读取一个字节的编号返回,读取完毕返回-1
// int code1 = is.read(); // 读取一滴水,一个字节
// System.out.println((char)code1);
//
// int code2 = is.read(); // 读取一滴水,一个字节
// System.out.println((char)code2);
//
// int code3 = is.read(); // 读取一滴水,一个字节
// System.out.println((char)code3);
//
// int code4 = is.read(); // 读取一滴水,一个字节 ,读取没有字节返回-1
// System.out.println(code4);
// 4.使用while读取字节数
// 定义一个整数变量存储字节
int ch = 0 ;
while((ch = is.read())!= -1){
System.out.print((char) ch);
}
// 读法优化,必须使用循环 // abc xyz i
// a.定义一个字节数组代表桶 // ooo ooo o
byte[] buffer = new byte[3];
int len ; // 存储每次读取的字节数。
while((len = is.read(buffer)) != -1){
// 读取了多少就倒出多少!
String rs = new String(buffer , 0 , len);
System.out.print(rs);
}
解决中文乱码
定义一个字节数组与文件的大小刚刚一样大,然后一桶水读取全部字节数据再输出
// 0.定位文件对象
File f = new File("C:\\Users\\Administrator\\Documents\\codes\\notes\\java-notes\\java补充知识点\\codes\\seniorJava\\day09\\src\\com\\itheima\\_25字节流的使用\\FileInputStreamDemo03.java");
// 1.定义一个字节输入流通向源文件路径,简化写法!
InputStream is = new FileInputStream(f);
// 2.定义一个字节数组与文件的大小刚刚一样大
// System.out.println("文件大小:"+f.length());
// byte[] buffer = new byte[(int) f.length()];
// int len = is.read(buffer);
// System.out.println("读取了:"+len);
// String rs = new String(buffer);
// System.out.println(rs);
byte[] buffer = is.readAllBytes();
String rs = new String(buffer);
System.out.println(rs);
FileOutputStream
文件字节输出流
作用:以内存为基准,把内存中的数据,按照字节的形式写出到磁盘文件中去。简单来说,把内存数据按照字节写出到磁盘文件中去。
构造器:
public FileOutputStream(File file)
:创建一个字节输出流管道通向目标文件对象。public FileOutputStream(String file)
:创建一个字节输出流管道通向目标文件路径。public FileOutputStream(File file , boolean append)
:创建一个追加数据的字节输出流管道通向目标文件对象。public FileOutputStream(String file , boolean append)
:创建一个追加数据的字节输出流管道通向目标文件路径。方法:
public void write(int a)
:写一个字节出去 。
public void write(byte[] buffer)
:写一个字节数组出去。
public void write(byte[] buffer , int pos , int len)
:写一个字节数组的一部分出去。
参数一,字节数组;参数二:起始字节索引位置,参数三:写多少个字节数出去。
- 字节输出流只能写字节出去
- 字节输出流默认是覆盖数据管道
- 换行用:
os.write("\r\n".getBytes());
- 关闭和刷新:刷新流可以继续使用,关闭包含刷新数据但是流就不能使用了!
FileOutputStream
字节输出流每次启动写数据的时候都会先清空之前的全部数据
字节是计算机中一切文件的组成,所以字节流适合做一切文件的复制。
复制是把源文件的全部字节一字不漏的转移到目标文件,只要文件前后的格式一样,绝对不会有问题。
复制步骤:
InputStream is = null ;
OutputStream os = null ;
try{
/** (1)创建一个字节输入流管道与源文件接通。 */
is = new FileInputStream("D:\\itcast\\图片资源\\meinv.jpg");
/** (2)创建一个字节输出流与目标文件接通。*/
os = new FileOutputStream("D:\\itcast\\meimei.jpg");
/** (3)创建一个字节数组作为桶*/
byte[] buffer = new byte[1024];
/** (4)从字节输入流管道中读取数据,写出到字节输出流管道即可。*/
int len = 0;
while((len = is.read(buffer)) != -1){
// 读取多少就倒出多少
os.write(buffer, 0 , len);
}
System.out.println("复制完成!");
}catch (Exception e){
e.printStackTrace();
} finally {
/**(5)关闭资源! */
try{
if(os!=null)os.close();
if(is!=null)is.close();
}catch (Exception e){
e.printStackTrace();
}
}
JDK1.7 开始之后释放资源的新方式
try-with-resources:
try(
// 这里只能放置资源对象,用完会自动调用close()关闭
){
}catch(Exception e){
e.printStackTrace();
}
什么是资源?
try(
/** (1)创建一个字节输入流管道与源文件接通。 */
InputStream is = new FileInputStream("D:\\itcast\\图片资源\\meinv.jpg");
/** (2)创建一个字节输出流与目标文件接通。*/
OutputStream os = new FileOutputStream("D:\\itcast\\meimei.jpg");
/** (5)关闭资源!是自动进行的 */
){
/** (3)创建一个字节数组作为桶*/
byte[] buffer = new byte[1024];
/** (4)从字节输入流管道中读取数据,写出到字节输出流管道即可。*/
int len = 0;
while((len = is.read(buffer)) != -1){
// 读取多少就倒出多少
os.write(buffer, 0 , len);
}
System.out.println("复制完成!");
}catch (Exception e){
e.printStackTrace();
}