此笔记是我听课程
尚硅谷_Java零基础教程-java入门必备-适合初学者的全套完整版教程
记录的老师课上的笔记。老师的笔记主要为.edf格式。我将其整理为Markdown格式。
其实有点标题党了。。 。java 基础编程部分我记录的不是很全,下面链接有java基础部分老师的笔记。java高级编程部分我是全的,而且链接中没有。
尚硅谷Java学科全套教程
下载地址:https://pan.baidu.com/s/1Kg7UUpO3wwALX6x28cWA7A
提取码:8op3
文章目录
- Java基础编程
- Java高级编程
Java基础编程
一、Java语言概述
JDK、JRE、JVM的关系
1.jdk=jre+java的开发工具集(javac.exe,java.exe,javadoc.exe)
2.jre=jvm+javaSE核心类库
JAVA语言特点
1.面向对象性
两个要素:类、对象
三个特征:封装、继承、多态
2.健壮性
3.跨平台性
二、基本语法
关键字和标识符
关键字
保留字 goto、const
标识符规则
1.由26个英文字母大小写,0-9,_或$组成
2.数字不可以开头
3.不可以使用关键字和保留字
4.Java中严格区分大小写,长度无限制
5.标识符不能包含空格
命名规范
包名:小写 xxyy
类名,接口名:首字符大写 XxYy
变量名、方法名:第一个单词小写后面每个单词首字母大写 xxYy
常量名:大写,下划线连接 XX_YY
变量的使用
基本数据类型
1、整型常量默认为int,浮点型常量默认为double
2、float 型数据声明要加f,F(不加会报错)
long 型数据声明加上l,L
3、char c=‘\u0043’ //C
4、UTF-8 编码规则
对于单字节的UTF-8编码,该字节的最高位为0,其余7位用来对字符进行编码(等同于ASCII码)。
对于多字节的UTF-8编码,如果编码包含n个字节,那么第一个字节的前n位1,第一个字节的第n+1位为0,该字节的剩余各位用来对字符进行编码。在第一个字节之后的所有的字节,都是最高两位为“10”,其余6位用来对字符进行编码。
四、面向对象-上
类与对象
JVM
虚拟机栈:即为平时提到的栈结构。局部变量存储在栈结构中
堆:new出来的结构(比如:数组、对象)加载在此空间中。补充:对象的属性(非static的)加载在堆空间中。
方法区:类的加载信息、常量池、静态域
类图
访问权限
jdk包介绍
五、面向对象-中
面向对象的特征二:继承性
方法的重写
关键字:super
子类对象实例化全过程
面向对象的特征三:多态性
Object类的使用
==与equals
1.只是一个方法,而非运算符
2.只能适用于引用数据类型
3.Object类中的equals()的定义
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个实体对象
4.像String、Date、File、包装类等都重写了Object类中的equals方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同
5.自定义类需要对Object类中的equals()进行重写
==运算符的使用
可以使用在基本数据类型变量和引用数据类型变量中
如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等(不一定类型要相同)
如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
单元测试方法
包装类的使用
数据类型转换
基本数据类型、包装类与String三者之间转换
//自动装箱、自动拆箱
Integer i = 10;
//基本数据类型、包装类--->String valueOf(Xxx xx)
//String--->基本数据类型、包装类 parseXxx(String s)
int i1 = Integer.parseInt("123");
String s = String.valueOf(i);
六、面向对象-下
static
static对象存在方法区中
单例模式
饿汉式
public class SingletonTest1 {
Bank s=Bank.getInstance();
}
//饿汉式
class Bank{
private Bank(){
};
private static Bank instance=new Bank();
public static Bank getInstance()
{
return instance;
}
}
懒汉式
public class SingletonTest2 {
public static void main(String[] args) {
Order o1=Order.getInstance();
Order o2=Order.getInstance();
System.out.println(o1==o2);
}
}
//懒汉式
class Order
{
private Order(){
};
private static volatile Order instance=null;
//线程不安全
/*
public static Order getInstance()
{
if(instance==null)
{
instance=new Order();
}
return instance;
}
*/
public static Order getInstance()
{
if(instance==null)
{
synchronized (Order.class)
{
if(instance==null)
instance=new Order();
}
}
return instance;
}
}
代理模式
静态代理
/*
接口的应用:代理模式
*/
public class ProxyTest {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork {
public void browse();
}
//被代理类
class Server implements NetWork {
@Override
public void browse() {
System.out.println("server browse");
}
}
class ProxyServer implements NetWork {
private NetWork work;
public ProxyServer(NetWork work) {
this.work = work;
}
public void check() {
System.out.println("check");
}
@Override
public void browse() {
check();
work.browse();
}
}
工厂模式
简单工厂
public class FactoryTest {
public static void main(String[] args) {
Car audi = CarFactory.getAudi();
Car audi1 = CarFactory.getCar("audi");
}
}
class CarFactory
{
public static Car getAudi(){
return new Audi();
}
public static Car getCar(String type)
{
if("audi".equals(type))
return new Audi();
return null;
}
}
interface Car{
}
class Audi implements Car{
}
工厂方法
public class FactoryTest2 {
public static void main(String[] args) {
Car audi =new AudiFactory().getCar();
}
}
interface Factory{
Car getCar();
}
class AudiFactory implements Factory
{
public Car getCar(){
return new Audi();
}
}
interface Car{
}
class Audi implements Car{
}
main函数
1.main()方法作为程序的入口
2.main()方法也是一个普通的静态方法
3.main()方法可以作为我们与控制台交互的方式
//如何将控制台获取的数据传递给形参:String[] args?
//运行时:java 类名 “Tom" "Jerry" "123" "true"
System.out.println(args[0]);//"Tom"
System.out.println(args[3]);//true
System.out.println(args[4]);//报异常
类的结构:代码块
静态先行
public class Test {
public static void main(String[] args) {
Root a = new Root();
Root b = new Root();
}
}
class Root {
static {
System.out.println("static");
}
{
System.out.println("普通代码块");
}
public Root() {
System.out.println("构造器");
}
}
/*
static
普通代码块
构造器
普通代码块
构造器
*/
静态代码块
内部可以输出语句
随着类的加载而执行,而且只执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
非静态代码块
内部可以输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性等进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
属性赋值执行顺序
对属性可以赋值的位置:
①默认初始化
②显示初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过“对象.属性”或“对象.方法”的方式,进行赋值
执行的先后顺序:① - ② / ⑤ - ③ - ④
关键字:final
用途
可以用来修饰:类、方法、变量
具体的
1.final 用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类
2.final 用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();
3.final 用来修饰变量:此时的"变量"就称为是一个常量
3.1final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
3.2final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
static final
用来修饰属性:全局常量
native
调用c语言代码
关键字:abstract
关键字:interface
内部类
定义
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.
内部类的分类
1.成员内部类(静态、非静态 )
2.局部内部类(方法内、代码块内、构造器内)
成员内部类的理解
1.一方面,作为外部类的成员:
调用外部类的结构
可以被static修饰
可以被4种不同的权限修饰
2.另一方面,作为一个类:
类内可以定义属性、方法、构造器等
可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
可以被abstract修饰
成员内部类
1.如何创建成员内部类的对象?(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
//创建非静态的Bird内部类的实例(非静态的成员内部类):
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
2.如何在成员内部类中调用外部类的结构?
class Person{
String name = "小明";
public void eat(){
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
//Person.this.eat();
}
}
}
局部内部类的使用
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
注意点
在局部内部类的方法中(比如:show如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)的话,要求此局部变量声明为final的。
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本:可以省略final的声明
总结
成员内部类和局部内部类,在编译以后,都会生成字节码文件。
格式:
成员内部类:外部类 $ 内部类名.class
局部内部类:外部类 $ 数字 内部类名.class
七、异常处理
异常
异常的体系结构
java.lang.Throwable
|-----java.lang.Error:一般不编写针对性的代码进行处理。
|-----java.lang.Exception:可以进行异常的处理
*****|------编译时异常(checked)
**********|-----IOException
***************|-----FileNotFoundException
**********|-----ClassNotFoundException
*****|------运行时异常(unchecked,RuntimeException)
**********|-----NullPointerException
**********|-----ArrayIndexOutOfBoundsException
**********|-----ClassCastException
**********|-----NumberFormatException
**********|-----InputMismatchException
**********|-----ArithmeticException
从程序执行过程,看编译时异常和运行时异常
编译时异常:执行javac.exe命名时,可能出现的异常
运行时异常:执行java.exe命名时,出现的异常
常见的异常类型
//******************以下是运行时异常***************************
//ArithmeticException
@Test
public void test6(){
int a = 10;
int b = 0;
System.out.println(a / b);
}
//InputMismatchException
@Test
public void test5(){
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);
scanner.close();
}
//NumberFormatException
@Test
public void test4(){
String str = "123";
str = "abc";
int num = Integer.parseInt(str);
}
//ClassCastException
@Test
public void test3(){
Object obj = new Date();
String str = (String)obj;
}
//IndexOutOfBoundsException
@Test
public void test2(){
//ArrayIndexOutOfBoundsException
// int[] arr = new int[10];
// System.out.println(arr[10]);
//StringIndexOutOfBoundsException
String str = "abc";
System.out.println(str.charAt(3));
}
//NullPointerException
@Test
public void test1(){
// int[] arr = null;
// System.out.println(arr[3]);
String str = "abc";
str = null;
System.out.println(str.charAt(0));
}
//******************以下是编译时异常***************************
@Test
public void test7(){
// File file = new File("hello.txt");
// FileInputStream fis = new FileInputStream(file);
//
// int data = fis.read();
// while(data != -1){
// System.out.print((char)data);
// data = fis.read();
// }
//
// fis.close();
}
Java高级编程
八、多线程
程序、进程、线程的理解
程序
概念:是为了完成特定任务、用某种语言编写的一直指令的集合。即一段静态的代码。
进程
概念: 程序的一次执行过程,或者正在运行的一个程序。
说明:进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程
**概念:**进程可进一步细化为线程,是一个程序内部的一条执行路径。
说明:线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器,线程切换的开销小。
进程可以细化为多个线程。
每个线程,拥有自己独立的:栈,程序计数器
多个线程,共享同一个进程中的结构:方法区,堆
并发和并行
并行
多个CPU同时执行多个任务
并发
一个CPU(采用时间片)同时执行多个任务
创建线程的方法
实现Runnable
继承Thread
二者对比
开发中:优先选择实现Runnable接口的方式
原因:1、实现的方式没类的单继承性的局限性
2.实现的方式更适合来处理多个线程共享数据的情况。
联系:public class Thread implements Runnable
相同点:两种方式都需要重写run()方法,将线程要指向的逻辑声明在run()中
实现Callable接口
/**
* 第三种方法
* 创建一个实现Callable的实现类
* 1.创建Callable接口实现类的对象
* 2.将Callable接口实现类的对象传递到FutureTask构造器
* 3.将FutureTask对象作为参数传递到Thread类的构造器中
* 4.Thread对象调用start()方法
* 5.将FutureTask对象调用get()方法
*/
public class ThreadNew {
public static void main(String[] args) throws ExecutionException, InterruptedException {
NumThread numThread=new NumThread();
FutureTask task = new FutureTask(numThread);
new Thread(task).start();
Object s = task.get();
System.out.println(s);
}
}
class NumThread implements Callable{
@Override
public Object call() throws Exception {
return 100;
}
}
线程池
class NumberThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"test");
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"test1");
}
}
public class ThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new NumberThread());
executorService.execute(new NumberThread1());
//executorService.submit();//适合Callable
executorService.shutdown();
}
}
Thread常用方法
1.start():启动当前线程,调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前cpu的执行权
7.join():在线程a中调用线程b的join,此时线程a就进行阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
8.stop():已过时,当执行此方法时,强制结束当前线程
9.sleep(long millitime):让当前线程“睡眠指定的millitime毫秒,在指定的millitime毫秒时间内,当前线程是阻塞状态
10.isAlive():判断当前线程是否存活
线程优先级
1 .
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5 —>默认优先级
2.如何获取和设置当前线程的优先级
getPriority():获取线程的优先级
setPriority(int p):设置线程的优先级
说明:高优先级的线程要抢占低优先级CPU的执行权,但是只是从概论上讲,高优先级的线程高概率被执行。并不意味着只有当高优先级的线程执行完以后 ,低优先级的线程才执行
线程通信
wait() /notify()/notifyAll() :定义在Object类中
守护线程
Java中的线程分为两类:一种是守护线程,一种是用户线程
-
它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
-
守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
-
java垃圾回收就是一个典型的守护线程
-
若 JVM中都是守护线程,当前JVM将退出
-
形象理解:兔死狗烹,鸟尽弓藏
线程的生命周期
线程的同步机制
synchronized
同步代码块
synchronized(同步监视器){
//需要被同步的代码
}
synchronized(this)
synchronized(xx.class)
1.操作共享数据的代码,即为需要被同步的代码
2.共享数据:多个线程共同操作的变量。
3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。要求:多个线程必须要共用同一把锁
同步方法
//实现Runnable接口型
public synchronized void fun(){
}
//继承Thread 需要用静态方法 保证同步监视器是同一个对象
public static synchronized void fun(){
}
Lock
synchronized 与Lock的异同
相同:二者都可以解决线程安全问题
不同:synchronized机制在执行完相应的同步代码后,自动的释放同步监视器。Lock需要手动的启动同步(lock()方法,同时结束同步也需要手动的实现unlock())
线程通信
线程通信涉及到的三个方法
wait():当前线程就进入阻塞状态,并释放同步监视器
notify():唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个
notifyAll():就会唤醒所有被wait
sleep()和wait()的异同
1.相同点:一旦执行方法,都可以使当前的线程进入阻塞状态
2.不同点 :
两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
调用的要求不同:sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或同步方法中
关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁
释放锁的操作
- 当前线程的同步方法、同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到了break、return终止了该代码块、方法的继续执行
- 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
- 当前线程在同步代码块、同步方法中执行了线程对象的wait( ) 方法,当前线程暂停,并释放锁
不会释放锁的操作
- 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
- 线程执行同步代码块时,其他线程调用了此线程的suspend()方法将该线程挂起,该线程不会释放锁(应尽量避免使用suspend()和resume()来控制线程)
九、Java常用类
String
一道题
public class StringTest {
String str = new String("good");
char[] ch = {
't', 'e', 's', 't'};
public void change(String str, char[] ch) {
str = "test ok";
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.println(ex.str);//good
System.out.println(ex.ch);//best
}
}
String概述
String:字符串,使用一对“”引起来表示
1.String声明为final的,不可被继承
2.String实现了Serializable接口,表示字符串是支持序列化的,实现了Comparable接口,表示String可以比较大小
3.String内部定义了final char[] value用于存储字符串数据
4.通过字面量的方式(区别于new给一个字符串赋值,此时的字符串值声明在字符串常量池中)
5.字符串常量池不会存储相同内容的字符串
String的不可变性
1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
3.当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
字符串拼接的比较
- 常量与常量的拼接结果在常量池,且常量池中不会存在相同内容的常量
- 只要其中有一个是变量,结果就在堆中
- 如果拼接 结果调用intern()方法,返回值就在常量池中
String 常用方法
public class StringMethodTest {
@Test
public void test1(){
String s1="Helloworld";
System.out.println(s1.length());
System.out.println(s1.charAt(0));
System.out.println(s1.isEmpty());
System.out.println(s1.toLowerCase());
System.out.println(s1.toUpperCase());
System.out.println(s1);
String s2=" hello ";
System.out.println(s2.trim());
String s3="helloWorld";
System.out.println(s1.equalsIgnoreCase(s3));
}
@Test
public void test2(){
String s1="Helloworld";
String s2=s1.concat("def");
System.out.println(s2);
String s3="abc";
String s4="abcd";
System.out.println(s3.compareTo(s4));
System.out.println(s2.substring(10));
System.out.println(s2.substring(0,10));
}
@Test
public void test3(){
String s1="hello";
System.out.println(s1.endsWith("llo"));
System.out.println(s1.startsWith("he"));
System.out.println(s1.startsWith("llo",2));
}
@Test
public void test4(){
String s1="helloworld";
System.out.println(s1.indexOf("world"));
System.out.println(s1.lastIndexOf("hello"));//从后往前找
}
@Test
public void test5(){
String s1="helloworld";
System.out.println(s1.replace('e','b'));
//replaceAll replaceFirst matches正则表达式
String tel="0571-4534289";
System.out.println(tel.matches("0571-\\d{7,8}"));
//split
}
}
String与其他结构的转换
与基本数据类型、包装类之间的转换
//String-->基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)
//基本数据类型、包装类-->String:调用String重载的valueOf(xxx)
@Test
public void test5(){
String str1="123";
int num=Integer.parseInt(str1);
Integer num1=Integer.valueOf(str1);
System.out.println(num);
System.out.println(num1);
String str2=String.valueOf(num);
System.out.println(str2);
}
与字符数组之间的转换
//String -->char[] 调用String的toCharArray()
//char[]-->String 调用String的构造器
@Test
public void test6(){
String str1="123";
char[] charArray=str1.toCharArray();
System.out.println(Arrays.toString(charArray));
char arr[]=new char[]{
'h','e','l','l','o'};
String str2=new String(arr);
System.out.println(str2);
}
与字节数组之间的转换
/*
String 与char[]的转换
*/
@Test
public void test1(){
String s1="abc123";
char a[]=s1.toCharArray();
char [] arr=new char[]{
'a','b'};
String s2=new String(arr);
System.out.println(a);
System.out.println(s2);
}
/*
String 与byte[]的转换
*/
@Test
public void test2() throws UnsupportedEncodingException {
String s1="abc123中";
byte[] bytes=s1.getBytes();
System.out.println(Arrays.toString(bytes));
byte[] bytes1=s1.getBytes("gbk");
System.out.println(Arrays.toString(bytes1));
//解码
String s2=new String(bytes,"UTF-8");
System.out.println(s2);
String s3=new String(bytes1,"gbk");
System.out.println(s3);
}
String StringBuffer和StringBuilder的转换
//String-->StringBuffer、StringBuilder 调用StringBuffer、StringBuilder的构造器
//StringBuffer、StringBuilder-->String 1.调用String的构造器2.StringBuffer、StringBuilder的toString()
@Test
public void test7(){
String str1="123";
StringBuilder stringBuilder=new StringBuilder(str1);
StringBuffer stringBuffer=new StringBuffer(str1);
String str2=stringBuffer.toString();
String str3=new String(stringBuffer);
}
JVM中字符串常量池存放位置
方法区(元空间)
StringBuffer、StringBuilder
String、StringBuffer、StringBuilder三者的比较
String:不可变的序列,底层char[]存储
StringBuffer:可变的字符序列,线程安全的,效率低;底层char[]存储
StringBuilder:可变的字符序列,线程不安全的,效率高;底层char[]存储
StringBuffer、StringBuilder内存解析
public class StringTest {
public static void main(String[] args) {
String str = new String();//char[] value=new char[0];
String str1 = new String("abc");//char[] value=new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value=new char[16];底层创建了一个长度是16的数组
System.out.println(sb1.length());//0
sb1.append('a');//value[0]='a';
StringBuffer sb2 = new StringBuffer("abc");//char[] value=new char[19];底层创建了一个长度是16+3的数组
System.out.println(sb2.length());//3
}
}
初始容量为16+字符串长度
扩容为原本容量的2倍+2,同时将原有数组中的元素复制到型的数组中。
StringBuffer、StringBuilder的常用方法
增:append(xxx)
删:delete(int start,int end)
改:setCharAt(int n,char ch)/replace(int start,int end,String str)
查:charAt(int n)
插:insert(int offset,xxx)
长度:length()
遍历:for()+charAt()/toString()
JDK8之间的时间API
获取系统当前时间
System类中的currentTimeMillis()
long time=System.currentTimeMillis();
//返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
//时间戳
java.util.Date与java.sql.Date
/*
1.两个构造器的使用
2.两个方法的使用
toString
getTime
*/
@Test
public void test2() {
Date date=new Date();
System.out.println(date.toString());
System.out.println(date.getTime());
Date date2 =new Date(1609166755679L);
System.out.println(date2.toString());
}
/*
Date与java.sql.Date的转换
*/
@Test
public void test3() {
Date date =new Date(1609166755679L);
java.sql.Date date2=new java.sql.Date(date.getTime());
System.out.println(date2.toString());
}
SimpleDateFormat
@Test
public void testSimpleDateFormat(){
SimpleDateFormat sdf=new SimpleDateFormat();
Date date=new Date();
System.out.println(date);
// 格式化: 日期-->字符串
String format =sdf.format(date);
System.out.println(format);
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String format1=sdf1.format(date);
System.out.println(format1);
}
@Test
public void test2() throws ParseException {
//字符串-->日期
SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date =sdf1.parse("2020-12-29 11:18:52");
System.out.println(date);
}
Calendar
日期类,抽象类。可变性
@Test
public void test1(){
//两种实例化方法
//创建其子类GregorianCalendar
//调用其静态方法
Calendar calendar=Calendar.getInstance();
System.out.println(calendar.getClass());
//get()
int days=calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
//set()
calendar.set(Calendar.DAY_OF_MONTH,22);
days=calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(days);
calendar.add(Calendar.DAY_OF_MONTH,3);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//getTime() 日历类 -->Date
Date time = calendar.getTime();
System.out.println(time);
//setTime() Date -->日历类
Date date1=new Date();
calendar.setTime(date1);
}
JDK8中新日期时间API
LocalDateTime、Instant、DateTimeFormatter
位于java.time包及子包
@Test
public void test1(){
//now() 获取当前的日期时间
LocalDate date=LocalDate.now();
LocalTime time =LocalTime.now();
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(date);
System.out.println(time);
System.out.println(localDateTime);
//of()设定指定的时间
LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 10, 10, 10, 10);
System.out.println(localDateTime1);
//getXxx()
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getDayOfWeek());
System.out.println(localDateTime.getMonth());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getMinute());
//体现不可变性 withXxx()设置相关的属性
LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(22);
System.out.println(localDateTime);
System.out.println(localDateTime2);
//
LocalDateTime localDateTime3 = localDateTime.plusDays(10);
System.out.println(localDateTime3);
LocalDateTime localDateTime4 = localDateTime.minusDays(10);
System.out.println(localDateTime4);
}
@Test
public void test2(){
//now()获取本初子午线对应的标准时间
Instant instant=Instant.now();
System.out.println(instant);
//添加时间的偏移量
OffsetDateTime offsetDateTime=instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
//获取毫秒数
long l = instant.toEpochMilli();
System.out.println(l);
//获取自1970年开始的毫秒数
Instant instant1=Instant.ofEpochMilli(1609337675361L);
System.out.println(instant1);
}
/*
DateTimeFormatter:格式化或解析日期、时间
类似于SimpleDateFormat
*/
@Test
public void test3(){
//方法一:预定义的标准形式
//格式化 日期->字符串
DateTimeFormatter formatter=DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime localDateTime=LocalDateTime.now();
String str1=formatter.format(localDateTime);
System.out.println(str1);
//解析 字符串-->日期
TemporalAccessor parse = formatter.parse("2020-12-30T22:21:53.3260412");
System.out.println(parse);
//方法二:本地化相关的格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
String str2 = formatter1.format(localDateTime);
System.out.println(str2);
//方法三:自定义的格式
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String str3 = formatter2.format(localDateTime);
System.out.println(str3);
TemporalAccessor parse1 = formatter2.parse("2020-12-30 10:27:21");
System.out.println(parse1);
}
Java比较器
Comparable或Comparator
Comparable接口的方式一旦确定,保证Comparable接口实现类的对象在任何位置都可以比较大小
Comparator接口属性临时性的比较
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
/**
* Comparable或Comparator
*/
public class CompareTest {
/*
1、包装类实现了Comparable接口,重写了compareTo()方法
2、从小到大
3、重写compareTo(obj)的规则
this大于obj返回正整数
小于负整数
等于返回0
*/
@Test
public void test1(){
String[] arr=new String[]{
"avc","ade","bd","ac"};
Arrays.sort(arr);
for (String s : arr) {
System.out.println(s);
}
}
@Test
public void test2(){
Goods[] arr=new Goods[4];
arr[0]=new Goods("asdas",34);
arr[1]=new Goods("qqdasd",22);
arr[2]=new Goods("aasd",34);
arr[3]=new Goods("qadasd",22);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
/*
Comparator
*/
@Test
public void test3(){
Goods[] arr=new Goods[4];
arr[0]=new Goods("asdas",34);
arr[1]=new Goods("qqdasd",22);
arr[2]=new Goods("aasd",34);
arr[3]=new Goods("qadasd",22);
Arrays.sort(arr,new GoodsComparator());
System.out.println(Arrays.toString(arr));
}
}
class GoodsComparator implements Comparator
{
@Override
public int compare(Object o1, Object o2) {
Goods goods=(Goods)o1;
Goods goods1=(Goods)o2;
if(goods.getPrice()>goods1.getPrice())
return 1;
else if(goods.getPrice()<goods1.getPrice())
return -1;
else
return goods.getName().compareTo(goods1.getName());
}
}
其他类
System Math BigInteger BigDecimal
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部,该类位于java.lang包
由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类,其内部的成员变量和成员方法都是static的 。
方法:
native long currentTimeMillis()
void exit(int status)
void gc()
String getProperty(String key)
@Test
public void test1(){
System.out.println(System.currentTimeMillis());
System.out.println(System.in.getClass());
System.out.println(System.out.getClass());
System.gc();//请求垃圾回收,至于是否立即回收,取决于系统中的垃圾回收算法的实现以及系统执行时的情况
//System.exit();
System.out.println(System.getProperty("java.version"));
System.out.println(System.getProperty("java.home"));
System.out.println(System.getProperty("os.name"));
System.out.println(System.getProperty("os.version"));
System.out.println(System.getProperty("user.name"));
System.out.println(System.getProperty("user.home"));
System.out.println(System.getProperty("user.dir"));
}
十、枚举类和注解
枚举类
枚举类常用方法(继承于java.lang.Enum)
Season spring = Season.SPRING;
//toString()返回枚举类对象的名称
System.out.println(spring.toString());
//values()返回所有枚举类对象构成的数组
Season[] values = Season.values();
for (Season value : values) {
System.out.println(value);
}
//valueOf(String objName) 返回枚举类中对象名是objName的对象
Season winter = Season.valueOf("WINTER");
System.out.println(winter);
System.out.println(winter.name());
System.out.println(Season.class.getSuperclass());
使用enum定义枚举类之后,如何让枚举类对象分别实现接口
//使用enum关键字定义的枚举类实现接口的情况
//情况一:实现接口,在enum类中实现抽象方法
//情况二:让枚举类的对象分别实现接口中的抽象方法 匿名内部类
enum Season implements Info {
//public static final
SPRING("spring", "test") {
@Override
public void show() {
System.out.println("spring");
}
},
SUMMER("summer", "test") {
@Override
public void show() {
System.out.println("summer");
}
},
AUTUMN("autumn", "test") {
@Override
public void show() {
System.out.println("autumn");
}
},
WINTER("winter", "test") {
@Override
public void show() {
System.out.println("winter");
}
};
private final String seasonName;
private final String seasonDesc;
Season(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
注解
生成文档相关的注解
- @author标明开发该模块的作者。多个作者之间使用,分割
- @version标明该类模块的版本
- @see参考转向,也就是相关主题
- @since从哪个版本开始增加的
- @param对方法中某参数的说明,如果没有参数就不能写
- @return 对方法返回值的说明,如果方法的返回值类型是void就不能写
- @exception 对方法可能抛出的异常进行说明,如果方法没有用throws显式抛出的异常就不能写
其中
- @param @return和@exception这三个标记都是只用于方法的
- @param的格式要求:@param 形参名 形参类型 形参说明
- @return的格式要求:@return 返回值类型 返回值说明
- @exception的格式要求:@exception 异常类型 异常说明
- @param 和@exception可以并列多个
注解的使用示例
示例一:生成文档相关的注解
示例二:在编译时进行格式检查(JDK内置的几个基本注解)
@Override:限定重写父类方法,该注解只能用于方法
@Deprecate:用于表示所修饰的元素(类,方法等)已过时,通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings:抑制编译器警告
示例三:跟踪代码依赖性,实现替代配置文件功能
如何自定义注解
参考源码的
@Repeatable(MyAnnotations.class)
@Target({
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
String value() default "hh";
}
元注解
@Target 可以使用的地方
@Retention 生命周期
@Documented 提取为文档
@Inherited 继承性
通过反射获取信息
jdk8新增注解功能
1可重复注解
在MyAnnotation上声明@Repeatable 中放MyAnnotations.class
MyAnnotations中放MyAnnotation数组
2类型注解
ELementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如:泛型声明)
ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中
十一、Java集合
集合
集合框架
集合框架
|----Collection接口:单列集合,用来存储一个一个的对象
****|----List接口:存储有序的、可重复的数据
************|----ArrayList、LinkedList、Vector
****|----Set接口:存储无序的、不可重复的数据
************|----HashSet、LinkedHashSet、TreeSet
|----Map接口:双列集合,用来存储一对(key-value)数据
************|----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
Collection接口
Collection接口常用方法
add(Object obj)
addAll(Collection coll)
size()
isEmpty()
clear()
contains(Object obj)
containsAll(Collection coll)
remove(Object obj)
removeAll(Collection coll)
retainsAll(Collection coll):仅保留此 collection 中那些也包含在指定 coll 的元素
equals(Object obj)
hasCode()
toArray()
iterator()
Collection集合与数组间的转换
//集合--->数组:toArray
ArrayList<String> list=new ArrayList<>();
list.add("123");
list.add("abc");
Object[] array = list.toArray();
System.out.println(Arrays.toString(array));//[123, abc]
//数组---集合:Arrays的静态方法asList()
List<Object> list1 = Arrays.asList(array);
System.out.println(list1.toString());//[123, abc]
使用Collection集合存储对象,要求对象所属的类满足:
向Collection接口的实现类中添加数据obj时,要求obj所在类要重写equals方法
Set要求重写hashcode
TreeSet要求实现Comparable或定制Compartor
迭代器
Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素
遍历
Iterator iterator = list.iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
迭代器的执行原理
remove()
Iterator iterator = list.iterator();
while(iterator.hasNext())
{
Object o = iterator.next();
if("Tom".equals(o))
{
iterator.remove();
}
}
增强for循环
for (Object o: list) {
System.out.println(o);
}
List
List存储数据的特点
List常用方法
List源码分析
ArrayList源码分析
LinkedList源码分析
Vector源码分析
存储元素要求
添加的对象,所在类要重写equals()方法
Set
存储的数据特点: 无序的、不可重复的元素
Set常用实现类
LinkedHashSet底层结构
Set存储元素的要求
Map
Map常用实现类
Map存储结构
Map常用方法
HashMap底层
HashMap属性说明
LinkedHashMap
TreeMap
Properties读取配置文件
public class PropertiesTest {
public static void main(String[] args) {
//key和value都是String
FileInputStream inputStream=null;
try {
Properties properties = new Properties();
inputStream = new FileInputStream("jdbc.properties");
properties.load(inputStream);
String name=properties.getProperty("name");
String password=properties.getProperty("password");
System.out.println(name+" "+password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream!=null)
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Collections
Collections常用方法
ArrayList 和HashMap都是线程不安全的,如果程序要求线程安全,使用synchronizedList(List list)和synchronized(Map map);
十二、泛型
自定义泛型类
泛型方法
public class Order<T> {
String orderName;
T orderT;
T [] arr =(T []) new Object[10];
public Order(){
}
public Order(String orderName,T orderT)
{
this.orderName=orderName;
this.orderT=orderT;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
//不是泛型方法
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
//泛型方法 可以static
public static <E> E test(E e){
return e ;
}
public static void main(String[] args) {
Order<String> order = new Order<String>("hello", "world");
System.out.println(order.getOrderName()+" "+order.getOrderT());
Integer t = order.test(123);
System.out.println(t);
}
}
泛型接口
注意事项
通配符
/**
* 通配符?
*/
@Test
public void test1(){
List<Object> list1=null;
List<String> list2=null;
List<?>list=null;
list=list1;
list=list2;
List<? super Object>list3;
List<? extends String>list4;
//list4=list1;报错
list4=list2;
//list3=list2;报错
list3=list1;
}
十三、IO流
File
File的实例化
File(String filePath)
File(String parentPath,String childPath)
File(File parentPath,String childPath)
相对路径和绝对路径
路径分隔符File提供一个常量 public static final String separator
File常用方法
IO流概论
流的分类
IO流体系
重点的流结构
抽象基类 | 节点类(文件流) | 缓存流(处理流的一种) |
---|---|---|
InputStream | FileInputStream(read(byte [] cbuf)) | BufferFileInputStream(read(byte [] cbuf)) |
OutputStream | FileOutputStream(write(byte[] buffer,0,len)) | BufferFileOutputStream(write(byte[] buffer,0,len)/flush()) |
Reader | FileReader(read(char [] cbuf)) | BufferFileReader(read(char [] cbuf)/readLine()) |
Writer | FileWriter(write(char[] cbuf,0,len)) | BufferFileWriter(write(char[] cbuf,0,len)/flush()) |
输入输出的标准化过程
**1.输入过程 **
创建File类的对象,指明读取的数据的来源
创建相应的输入流,将File类的对象作为参数,传入流的构造器中
具体的输入过程 创建相应的byte[]或char[]
关闭流资源
**2.输出过程 **
创建File类的对象,指明读取的数据的来源
创建相应的输出流,将File类的对象作为参数,传入流的构造器中
具体的输出过程 write(char[]/byte[] buffer,0,len)
关闭流资源
需要try-catch-finally处理
节点流
FileRead FileWrite
File file = new File("hello.txt");
FileReader fileReader = null;
try {
fileReader = new FileReader(file);
char[] cbuf=new char[5];
int len ;
while((len=fileReader.read(cbuf))!=-1){
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
// String s=new String(cbuf,0,len);
// System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileWrite
/**
* 文件不存在则会自动创建
* new FileWriter(file,boolean) 默认为false为覆盖
*/
@Test
public void testFileWrite(){
File file = new File("hello1.txt");
FileWriter fileWriter= null;
try {
fileWriter = new FileWriter(file,true);
fileWriter.write("hhh");
//fileWriter.append("appendTest\n");
//fileWriter.append("appendTest\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文本文件的复制
@Test
public void testFileReadFileWrite(){
File srcFile = new File("hello.txt");
File destFile=new File("hello1.txt");
FileReader fr=null;
FileWriter fw=null;
try {
fr=new FileReader(srcFile);
fw = new FileWriter(destFile);
int data;
char[] cbuf=new char[5];
int len ;
while((len=fr.read(cbuf))!=-1) {
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream、FileOutputStream
1.对于文本文件(.txt,.java,.c,.cpp)使用字符流
2.对于非文本文件(.jpg,.mp3,.avi,.doc,.ppt)使用字节流
缓冲流
BufferedRead BufferedWrite
BufferedInputStream BufferedOutputStream
File srcFile = new File("5.jpg");
File destFile=new File("6.jpg");
FileInputStream fis=null;
FileOutputStream fos=null;
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
fis=new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
bis=new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
int data;
long start = System.currentTimeMillis();
while((data=bis.read())!=-1) {
bos.write(data);
}
System.out.println(System.currentTimeMillis()-start);
} catch (IOException e) {
e.printStackTrace();
} finally {
//在关闭外层流的同时,内层也会自动关闭
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流
InputStreamReader
将一个字节的输入流转换为字符的输入流
解码:字节、字节数组 —>字符数组、字符串
OutputStreamWriter
将一个字符的输出流转换为字节的输出流
编码:字符数组、字符串 —>字节、字节数组
编码决定了解码的过程
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("hello.txt");
//InputStreamReader isr=new InputStreamReader(fis); 使用系统默认
InputStreamReader isr=new InputStreamReader(fis, StandardCharsets.UTF_8);
char[] cbuf=new char[20];
int len;
while((len=isr.read(cbuf))!=-1)
{
String str=new String(cbuf,0,len);
System.out.print(str);
}
isr.close();
}
@Test
public void test2() throws IOException {
FileInputStream fis = new FileInputStream("hello.txt");
FileOutputStream fos=new FileOutputStream("hello2.txt");
InputStreamReader isr=new InputStreamReader(fis, StandardCharsets.UTF_8);
OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
char[] cbuf=new char[20];
int len;
while((len=isr.read(cbuf))!=-1)
{
osw.write(cbuf,0,len);
}
isr.close();
osw.close();
}
编码表
其他流的使用
标准的输入输出流
System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
修改默认的输入输出行为:
System类的setIn(InputStream is)/setOut(PrintStream ps)
打印流
PrintStream PrintWrite
提供了一系列重载的print和println方法,用于多种数据类型的输出
System.out返回的是PrintStream的实例
PrintStream ps=new PrintStream(new FileOutputStream("text.txt"),true);
System.setOut(ps);//把标准输出流改为文件
for (int i = 0; i < 255; i++) {
System.out.print((char)i);
if(i%50==0)
System.out.println();
}
ps.close();
数据流
DataInputSteam DataOutputStream
//数据流,用于读取或写成基本数据类型的变量或字符串
@Test
public void test3() throws IOException {
DataOutputStream dos=new DataOutputStream(new FileOutputStream("hello3.txt"));
dos.writeUTF("你好");
dos.flush();
dos.writeDouble(123.00);
dos.flush();
dos.close();
}
@Test
public void test4() throws IOException {
DataInputStream dis=new DataInputStream(new FileInputStream("hello3.txt"));
String s = dis.readUTF();
System.out.println(s);
double v = dis.readDouble();
System.out.println(v);
}
对象流
ObjectInputStream和ObjectOutputStream
ObjectInputSteam 内存中的对象->存储中的文件、通过网络传输出去 序列化
ObjectOutputSteam存储中的文件、通过网络接收进来->内存中的对象 反序列化
对象的序列化机制
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制文件,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另外一个网路节点。//当其它程序获取了这种二进制流,就可以恢复成原本的Java对象
代码实现
//序列化
@Test
public void testObjectOutputStream() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Object.dat"));
oos.writeObject(new String("你好"));
oos.flush();
oos.writeObject(new Person("wzh", 22, 1,new Account(123)));
oos.flush();
oos.close();
}
//反序列化
@Test
public void testObjectInputStream() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.dat"));
Object o = ois.readObject();
System.out.println(o);
o = ois.readObject();
System.out.println(o);
ois.close();
}
transient
static和transient修饰的成员变量,序列化对象的时候,这个属性就不会被序列化
RandomAccessFile
随机存储文件流
1.注解继承于java.lang.Object类,实现了DataInput 和DataOutput接口
2.即可作为输入流,也可作为输出流
3.作为输出流时,写出的文件如果不存在,则新建,否则为从头覆盖
4.可以通过相关的操作,实现插入的操作
public void test1() throws IOException {
RandomAccessFile file=new RandomAccessFile("5.jpg","r");
RandomAccessFile file2=new RandomAccessFile("9.jpg","rw");//rw
byte[]buff=new byte[1024];
int len;
while((len=file.read(buff))!=-1)
{
file2.write(buff,0,len);
}
file.close();
file2.close();
}
//插入
@Test
public void test4()throws IOException{
RandomAccessFile raf1=new RandomAccessFile("hello.txt","rw");
raf1.seek(3);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte [] buffer=new byte[20];
int len;
while((len=raf1.read(buffer))!=-1)
{
baos.write(buffer,0,len);
}
raf1.seek(3);
raf1.write("xyz".getBytes());
raf1.write(baos.toString().getBytes());
raf1.close();
}
Path、Paths、Files
NIO的使用说明
Java NIO(New IO,Non-Blocking IO)是从Java1.4版本开始引入的一套新的IO API,可以替代标准的Java IO API。
NIO与原来的IO同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓存区的(IO是面向流的)、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作
Path的实例化
path替换原本的File类
Paths类提供的静态get()方法用来获取Path对象
static Path get(String first,String …more):用于将多个字符串连成路径
static Path get(URI url):返回指定uri对应的Path路径
Path常用方法
String toString(): 返回调用Path对象的字符串表示形式
boolean startsWith(String Path):测试此路径是否以 Path开始
boolean endsWith(String Path):测试此路径是否以 Path结束
boolean isAbsolute():判断是否是绝对路径
Path getParent():返回父路径
Path getRoot():返回根路径
Path getFileName():将此路径表示的文件或目录的名称返回
int getNameCount():返回路径中的名称元素的数量
Path getName(int idx):返回指定索引位置idx的路径名称
Path toAbsolutePath():作为绝对路径返回调用Path对象
Path resolve(Path p):合并两个路径,返回合并后的路径对应的Path对象
File toFile():将Path转换为File类的对象
Files常用方法
Path copy(Path source, Path target, CopyOption… options) :文件的复制
Path createDirectory(Path dir, FileAttribute<?>… attrs) :创建一个新的目录
Path createFile(Path path, FileAttribute<?>… attrs) :创建一个文件,如果该文件已存在失败
void delete(Path path) :删除文件/目录,如果不存在,执行报错
void deleteIfExists(Path path) :Path对应的文件/目录如果存在,执行删除。
Path move(Path source, Path target, CopyOption… options) :将文件移动或重命名为目标文件
long size(Path path) :返回文件的大小(以字节为单位)。
Files常用方法:用于判断
boolean exists(Path path, LinkOption… options)
测试文件是否存在boolean isDirectory(Path path, LinkOption… options) :测试文件是否是目录
boolean isRegularFile(Path path, LinkOption… options) :测试文件是否是文件
boolean isHidden(Path path) :测试文件是否是隐藏文件
boolean isReadable(Path path) :测试文件是否可读
boolean isWritable(Path path) :测试文件是否可写
boolean notExists(Path path, LinkOption… options) :测试此路径所在的文件是否不存在
Files常用方法:用于操作内容
SeekableByteChannel newByteChannel(Path path, OpenOption… options) :打开或创建文件,返回可访问的字节通道以访问该文件,options指定打开方式。
DirectoryStream
newDirectoryStream(Path dir) :打开path指定的目录 InputStream newInputStream(Path path, OpenOption… options):获取InputStream对象
OutputStream newOutputStream(Path path, OpenOption… options) :获取OutputStream对象
十四、网络编程
InetAddress
网络通信的两个要素
IP和端口号
TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
InetAddress实例化
InetAddress address = InetAddress.getByName("192.168.10.14");
System.out.println(address);
InetAddress address1 = InetAddress.getByName("www.baidu.com");
System.out.println(address1);
端口和Ip地址组合得到一个网络套接字Socket
网络通信协议
网络分层模型
TCP和UDP区别
TCP协议:
使用TCP协议前,续先建议TCP连接,形成传输数据通道
传输前,采用**“三次握手”**方式,点对点通信,是可靠的
TCP协议进行通信的两个应用程序:客户端、服务端
在连接中可进行大数据量的传输
传输完毕,需释放已建立的连接,效率低
UDP协议:
将数据、源、目的封装成数据包,不需要建议连接
每个数据报的大小限制在64K内
发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
可以广播发送
发送数据结束时无需释放资源,开销小,速度快
TCP三次握手四次挥手
TCP网络编程
客户端发送信息给服务器,服务器显示在控制台,并返回发送成功给客户端
@Test
public void client() throws Exception {
Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),8899);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello中国".getBytes());
socket.shutdownOutput();//发送完毕
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer=new byte[5];
int len;
while((len=is.read(buffer))!=-1)
{
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
baos.close();
is.close();
outputStream.close();
socket.close();
}
@Test
public void server() throws Exception{
ServerSocket serverSocket = new ServerSocket(8899);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos=new ByteArrayOutputStream();
byte[] buffer=new byte[5];
int len;
while((len=is.read(buffer))!=-1)
{
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
System.out.println(socket.getInetAddress().getHostAddress());
OutputStream os = socket.getOutputStream();
os.write("发送成功".getBytes());
os.close();
baos.close();
is.close();
socket.close();
serverSocket.close();
}
UDP网络编程
@Test
public void sender() throws IOException {
DatagramSocket socket = new DatagramSocket();
String str="你好";
byte[] data=str.getBytes();
InetAddress inet=InetAddress.getLocalHost();
DatagramPacket packet=new DatagramPacket(data,0,data.length,inet,9090);
socket.send(packet);
socket.close();
}
@Test
public void receiver()throws IOException{
DatagramSocket socket=new DatagramSocket(9090);
byte[] data=new byte[100];
DatagramPacket packet=new DatagramPacket(data,0,data.length);
socket.receive(packet);
System.out.println(new String(packet.getData(),0,packet.getLength()));
}
URL编程
URL
统一资源定位符,对应则互联网的某一资源地址
URL的5个基本结构
https://www.bilibili.com/video/BV1Kb411W75N?p=635
协议 主机名 端口号 资源地址 参数列表
实例化
URL url=new URL("https://www.bilibili.com/video/BV1Kb411W75N?p=628");
URL常用方法
public String getProtocol() 获取该URL的协议名
public String getHost() 获取该URL的主机名
public String getPort() 获取该URL的端口号
public String getPath() 获取该URL的文件路径
public String getFile() 获取该URL的文件名
public String getQuery() 获取该URL的查询名
数据的读取和下载
URL url=new URL("https://ss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/5882b2b7d0a20cf49a84743471094b36adaf99c1.jpg");
HttpsURLConnection urlConnection= (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream is = urlConnection.getInputStream();
FileOutputStream fis=new FileOutputStream(new File("1.jpg"));
byte[] buffer=new byte[1024];
int len;
while((len=is.read(buffer))!=-1)
{
fis.write(buffer,0,len);
}
fis.close();
is.close();
urlConnection.disconnect();
十五、Java反射机制
Class
获取Class的实例
//4种
Class<Person> clazz1 = Person.class;
Person p1=new Person();
Class<? extends Person> clazz2 = p1.getClass();
//调用Class的静态方法
Class<?> clazz3 = Class.forName("code.day23.Person");
System.out.println(clazz1==clazz2);
System.out.println(clazz1==clazz3);
//使用类的加载器
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
System.out.println(classLoader);
ClassLoader classLoaderParent = classLoader.getParent();
System.out.println(classLoaderParent);
ClassLoader classLoaderParent1 = classLoaderParent.getParent();
System.out.println(classLoaderParent1);
Class<?> clazz4 = classLoader.loadClass("code.day23.Person");
System.out.println(clazz4);
System.out.println(clazz1==clazz4);
Class实例可以是哪些结构
1.class
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
2.interface:接口
3.[]:数组
4.enum:枚举
5.annotation:注解@interface
6.primitive type:基本数据类型
7.void
Class c1 = Object.class;
Class c2=Comparator.class;
Class c3=String[].class;
Class c4=ElementType.class;
Class c5=Override.class;
Class c6=int.class;
Class c7=void.class;
Class<Class> c9 = Class.class;
int []a=new int[10];
int []b=new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
//只要元素类型和维度一样,就是同一个Class
System.out.println(c10==c11);//true
ClassLoader
类加载器的作用
将class文件字节码内存加载到内存中,并将这些静态数据转换为方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存
标准的JAVASE类加载器可以按要求查找类,一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收Class对象
类加载器分类
ClassLoader加载配置文件
Properties pros = new Properties();
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
pros.load(is);
String user=pros.getProperty("user");
System.out.println(user);
创建运行时对象
newInstance();
Class<Man> clazz = Man.class;
Man p = clazz.newInstance();
创建运行时完成结构
Filed
Class clazz=Man.class;
Field[] files=clazz.getDeclaredFields() ;
for (Field f:
files) {
System.out.println(f);
//权限修饰符
System.out.println(Modifier.toString(f.getModifiers()));
//数据类型
System.out.println(f.getType());
//变量名
System.out.println(f.getName());
}
Method
Class clazz=Man.class;
Method[] files=clazz.getDeclaredMethods() ;
for (Method m:
files) {
//注解
Annotation[] annotations=m.getAnnotations();
for (Annotation a :
annotations) {
System.out.println(a);
}
//权限修饰符
System.out.println(Modifier.toString(m.getModifiers()));
//返回值类型名
System.out.println(m.getReturnType().getName());
//方法名
System.out.println(m.getName());
//参数
Class[] pas=m.getParameterTypes();
if(pas!=null)
{
for(Class p:pas)
System.out.print(p.getName()+" ");
if(pas.length!=0)
System.out.println();
}
//异常
Class[] ets= m.getExceptionTypes();
if(ets!=null)
{
for(Class e:ets)
System.out.print(e.getName()+" ");
if(ets.length!=0)
System.out.println();
}
}
其他
@Test
public void test1() throws Exception{
Class<Man> clazz = Man.class;
//泛型父类
Type superclass =clazz.getGenericSuperclass();
ParameterizedType paramType=(ParameterizedType)superclass;
Type[] actualTypeArguments = paramType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
}
@Test
public void test2(){
Class<Man> clazz = Man.class;
//接口
Class [] interfaces = clazz.getInterfaces();
for (Class c:
interfaces) {
System.out.println(c);
}
Class [] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class c:
interfaces1) {
System.out.println(c);
}
}
@Test
public void test3(){
Class<Man> clazz = Man.class;
//包
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a :
annotations) {
System.out.println(a);
}
}
运行时类的指定结构
指定的方法
invoke(Object obj,Object… args)
Class<Man> clazz = Man.class;
Man p = clazz.newInstance();
Method show = clazz.getDeclaredMethod("show", String.class);
show.setAccessible(true);
Object returnValue = show.invoke(p, "CHN");
System.out.println(returnValue);
//静态方法 其中showDesc是静态方法
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
showDesc.invoke(Man.class);
指定的构造器、属性
newInstance
set(Object obj, Object value) get(Object obj)
Class clazz = Person.class;
Constructor constructor =clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("Tom", 12);
Person person = (Person) obj;
System.out.println(person.toString());
Field age = clazz.getDeclaredField("age");
age.set(person,10);
System.out.println(age.get(person));
动态代理
代理模式
使用 代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上
静态代理
interface ClothFactory{
void produceCloth();
}
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;
public ProxyClothFactory(ClothFactory factory)
{
this.factory=factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();;
System.out.println("代理过程做一些后续的收尾工作");
}
}
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批运动服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
NikeClothFactory nike=new NikeClothFactory();
ProxyClothFactory proxyClothFactory=new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
静态代理缺点
1.代理类和对象的类都是在编译期间确定下来,不利于程序的扩展
2.每个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
动态代理特点
动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象
动态代理的实现
需要解决的两个问题
1.如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
Proxy.newProxyInstance()实现
2.当通过代理类的对象调用方法a,如何动态的去调用被代理类中的同名方法a
InvocationHandler接口的实现类及其方法invoke()
interface Human{
String getBelief();
void eat(String food);
}
class SuperMan implements Human
{
@Override
public String getBelief() {
return "I believe i can fly";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃"+food);
}
}
class HumanUtil{
public static void method1(){
System.out.println("通用方法一");
}
public static void method2(){
System.out.println("通用方法二");
}
}
class ProxyFactory{
public static Object getProxyInstance(Object obj){
MyInvocationHandler handler=new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces()
,handler);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj ;
public void bind(Object obj){
this.obj =obj;
}
//当我们通过代理类的对象,调用方法a时就会自动的调用如下的方法invoke
//将被代理类要执行的方法a的功能就声明在invoke中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理类对象调用的方法,此方法也 就作为了被代理类对象要调用的方法
HumanUtil.method1();
Object returnValue = method.invoke(obj, args);
HumanUtil.method2();
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan=new SuperMan();
Human proxy=(Human)ProxyFactory.getProxyInstance(superMan);
System.out.println(proxy.getBelief());
proxy.eat("四川麻辣烫");
NikeClothFactory nikeClothFactory=new NikeClothFactory();
ClothFactory proxyInstance = (ClothFactory)ProxyFactory.getProxyInstance(nikeClothFactory);
proxyInstance.produceCloth();
}
}
十六、JAVA8新特性
java8新特性概述
Lambda表达式
举例
Runnable r1=()->System.out.println("hh");
Lambda表达式基本语法
1.举例:(o1,o2)->Integer.compare(o1,o2);
2.格式:
lambda操作符或箭头操作符
左边:lambda形参列表(其实就是接口中的抽象方法的形参列表)
右边:lambda体(其实就是重写的抽象方法的方法体)
使用:六种情况
@Test
public void test() {
//语法格式一:无参,无返回值
Runnable r1 = () -> {
System.out.println("hello");
};
//语法格式二:Lambda需要一个参数,但是没有返回值
Consumer<String> con = (String str) -> {
System.out.println(str);
};
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
Consumer<String> con1 = (str) -> {
System.out.println(str);
};
//语法格式四:Lambda若只需要一个参数时,参数的小括号可以省略
Consumer<String> con2 = str -> {
System.out.println(str);
};
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator<Integer> com = (x, y) -> {
System.out.println("hello");
return Integer.compare(x, y);
};
//语法格式六:当Lambda体只有一条语句,return与大括号若有,都可以省略
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
}
总结六种情况
左边:Lambda形参列表的参数类型可以省略(类型推断);如果Lambda形参列表只有一个参数,其一对()也可以省略
右边:Lambda体应该使用一对{}包裹;如果Lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字
函数式接口
定义
1.如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
2.我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口
3.Lambda表达式的本质:作为函数式接口的实例
使用
java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回值类型 | 用途 |
---|---|---|---|
Consumer消费型接口 | T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Suppelier供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get() |
Function<T,R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate断定型接口 | T | boolean | 确定类型为T的对象是否满足其约束,并返回boolean值。包含方法:boolean test(T t) |
总结
何时使用Lambda表达式
当需要对一个函数式接口的实例时,可以使用Lambda表达式
何时使用给定的函数式接口
如果开发中需要定义一个函数式接口,首先看在已有的jdk提供的函数式接口是否提供了能满足需求的函数式接口。如果有,则直接调用,不需要再自定义
方法引用
理解
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法
使用情景
当要传递给Lambda体的操作,已经有实现的方法,可以使用方法引用
格式
类(对象)::方法名
三种情况
1.对象::非静态方法
2.类::静态方法
3.类::非静态方法
要求
1.要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同(针对于情况1和情况2)
2.当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName(针对于情况3)
//对象::非静态方法
@Test
public void test2(){
Employee employee=new Employee(1001,"Tom",23,5600);
Supplier<String>supplier=employee::getName;
System.out.println(supplier.get());
}
//类::静态方法
@Test
public void test3(){
Comparator<Integer>com1=Integer::compareTo;
System.out.println(com1.compare(12, 21));
}
//类::静态方法
@Test
public void test4(){
Function<Double,Long>func= Math::round;
System.out.println(func.apply(12.6));
}
//类 ::非静态
@Test
public void test5(){
Comparator<String>com1=(s1,s2) ->s1.compareTo(s2);
Comparator<String>com2=String::compareTo;
System.out.println(com1.compare("A", "B"));
System.out.println(com2.compare("A", "B"));
}
构造器引用、数组引用
构造器引用格式
类名::new
构造器引用使用要求
和方法引用类上,函数式接口的抽象方法的形参列表和构造器的形参列表一致。抽象方法的返回值类型即为构造器所属的类的类型
数组引用格式
数组类型[]::new
@Test
public void test1() {
Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup1 = Employee::new;
System.out.println(sup.get());
System.out.println(sup1.get());
}
@Test
public void test2() {
Function<Integer, Employee> fun = Employee::new;
System.out.println(fun.apply(3));
}
//数组引用
@Test
public void test4() {
Function<Integer, String[]> fun1 = length -> new String[length];
String[] arr1 = fun1.apply(5);
System.out.println(Arrays.toString(arr1));
Function<Integer, String[]> fun2 = String[]::new;
String[] arr2 = fun1.apply(5);
System.out.println(Arrays.toString(arr2));
}
Stream API
理解
1.Stream关注的是对数据的运算,与CPU打交道
2.java8提供了一套api,使用这套api可以对内存中的数据进行过滤、排序、映射、归约等操作,类似于SQL对数据库中表的相关操作
注意点
1.Stream 自己不会存储元素
2.Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
3.Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
Stream使用流程
1.Stream的实例化
2.一系列的中间操作(过滤、映射、…)
3.终止操作
使用流程的注意点
1.一个中间操作链,对数据源的数据进行处理
2.一旦执行终止操作,就执行中间操作链,并产生结构。之后,不会再被使用
Stream实例化
1.通过集合2.通过数组3.Stream的of方法4.创建无限流
//通过集合
@Test
public void test1(){
List<Employee> employees = EmployData.getEmployee();
Stream<Employee> stream = employees.stream();
}
//通过数组
@Test
public void test2(){
IntStream stream = Arrays.stream(new int[]{
1, 2, 3});
Stream<String> stream1 = Arrays.stream(new String[]{
"1", "2", "3"});
}
//Stream的of方法
@Test
public void test3(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
}
//创建无限流
@Test
public void test4(){
//迭代
Stream.iterate(0,s->s+2).limit(10).forEach(System.out::println);
//生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
中间操作
1.筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的hashCode()和equals去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补 |
2.映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都转换为另一个流,然后将所有流连接成一个流 |
3.排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
终止操作
1.匹配与查找
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户去做迭代,称为外部抵达。相反,StreamAPI使用内部抵达,它帮你把迭代做了) |
2.归约
方法 | 描述 |
---|---|
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional |
备注:map和reduce的连接通常称为map-reduce模式,因google用它来进行网络搜索而出名
3.收集
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector需要使用Collectors提供实例
方法 | 返回类型 | 作用 |
---|---|---|
toList | List | 把流中元素收集到List |
toSet | Set | 把流中元素收集到Set |
toCollection | Collection | 把流中元素收集到创建的集合 |
举例
List<Employee>emps=list.stream().collect(Collections.toList());
Set<Employee>emps=list.stream().collect(Collections.toSet());
Collection<Employee>emps=list.stream().collect(Collections.toCollection(ArrayList::new));
Optional
理解
为了解决java中的空指针问题
Optional类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在,或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常。
@Test
public void test1(){
Girl girl = new Girl();
Optional<Girl> optionalGirl = Optional.of(girl);
System.out.println(optionalGirl);
Girl girl1=null;
//Optional.of(girl1);
Optional<Girl> optionalGirl1 = Optional.ofNullable(girl1);
Girl girl2 = optionalGirl1.orElse(new Girl("wzh"));
System.out.println(girl2);
}
public String getGirlName(Boy boy)
{
return boy.getGirl().getName();
}
public String getGirName2(Boy boy)
{
Optional<Boy> optionalBoy = Optional.ofNullable(boy);
Boy boy1 = optionalBoy.orElse(new Boy(new Girl("迪丽热巴")));
Girl girl=boy1.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
return girl1.getName();
}
//orElse和get
//ofNullable和orElse
@Test
public void test2(){
Boy boy=new Boy();
//boy=null;
//boy=new Boy(new Girl("wzh"));
String s = getGirName2(boy);
System.out.println(s);
}