重点:封装、继承、多态、接口
Day07日测 统计字符串中字母的重复次数
rethink:没有想到用变量来暂时寄存,再来比较;将count作为循环判断以后可以减少一定的判断次数
import java.util.Arrays;
public class Demo1 {
public static void main(String[] args) {
char [] arrs={'a','c','a','a','b','b'};
//记录字母种类
char[] arrs1=new char[arrs.length];
//记录字母种类个数
int[] nums=new int[arrs.length];
//总共重复字母次数的个数
int count=0;
for (int i = 0; i < arrs.length; i++) {
//c来暂时存储并依次进行比较
char c=arrs[i];
int index=-1;
for (int j = 0; j < count; j++) {
if(c==arrs[j]) index=j;
}
if(index==-1){
//如果该字母没有出现过,就添加到arrs1中并在对应的nums中次数设置为1
arrs1[count]=c;
nums[count]=1;
count++;
}else
//如果该字母出现过,对应的nums中次数加1
nums[index]=nums[index]+1;
}
//打印输出
for (int i = 0; i < arrs1.length; i++) {
System.out.println(arrs1[i]+"-----"+nums[i]+"\n");
}
}
}
数组建立
其中对象数组的默认值是NULL,对象数组存储的是对象的地址
//静态初始化
int[][] array00=new int[][]{{1,2,3},{2,5,6}};//第一种
int[][] array01={{1,2,3},{2,5,6}};//第二种
//动态初始化数组
int[][] array03=new int[5][6];//第一种
int[][] array04=new int[3][];//第二种
练习:手动输入小组数以及每个小组人数,并打印出成绩
import java.util.Arrays;
import java.util.Scanner;
public class Day07 {
public static void main(String[] args) {
System.out.println("group number");
Scanner sc = new Scanner(System.in);
int groupnum=sc.nextInt();
double[][]array= new double[groupnum][];
for (int i = 0; i < groupnum; i++) {
System.out.println(""+(i+1)+"'s merber number");
int merbernum=sc.nextInt();
double[] scores=new double[merbernum];//*****
array[i]=scores;//*******
for (int j = 0; j < merbernum; j++) {
System.out.println("第"+(i+1)+"组人分数依次为");
scores[j]=sc.nextDouble();
}
}
for (int i = 0; i < groupnum; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print("第"+(i+1)+"组第"+(j+1)+"个人的java-----"+array[i][j]+" ");
}
System.out.println();
}
}
}
对象数组的练习,代码如下:
public class Student {
String name;
double grade;
}
//对象数组
Student[] stu=new Student[5];
for (int i = 0; i < stu.length; i++) {
System.out.println("input "+(i+1)+" name");
Scanner sc=new Scanner(System.in);
Student student=new Student();
student.name=sc.next();
System.out.println("input "+(i+1)+" grade");
student.grade=sc.nextDouble();
stu[i]=student;
}
for (int i = 0; i < stu.length; i++) {
System.out.println(stu[i].name+"-----"+stu[i].grade);
}
}
方法重载
重载的条件:
- 必须在同一个类中
- 方法名必须相同
- 形参列表必须不同
- 和方法的返回值以及修饰符无关
类的五大成员
类:成员变量(成员变量和局部变量)、成员方法(实例方法和类方法)、构造器、初始化块、内部类(成员内部类、匿名内部类、静态成员内部类、方法(局部)内部类)
成员变量与局部变量的区别?
成员变量=实例变量 是在类中声明的 本类及其他类(符合修饰符) 有默认值 堆内存 对象回收时候销毁
局部变量 在方法中声明的 只能当前大括号内 必须初始化,才能够使用 栈内存 当前大括号运行完以后销毁
对象关联的话,要创建新的对象再赋值,如下:
public class Employee {
String name;
int age;
char gender;
Phone phone;
}
public class Phone {
String brand;
String name;
char color;
}
Employee employee=new Employee();
employee.age=12;
employee.name="阿刁";
employee.gender='女';
Phone phone=new Phone();
phone.brand="三星";
phone.name="阿刁的手机";
phone.color='红';
employee.phone=phone;//在这里将phone对象又返回到employee的phone中
System.out.println("姓名:"+employee.name+" 年龄:"+employee.age+" 性别:"+employee.gender+
" 手机品牌为:" +employee.phone.brand+ " 手机名字:"+employee.phone.name+" 手机的颜色:"+employee.phone.color);
参数传递机制
引用数据类型,栈内存存储的是地址,在方法传参的时候,就是地址传递(多个变量指向同一个堆内存或常量池)
基本数据类型,栈内存中存储的是值,在方法传参的时候就是值快递
局部变量在栈区,全局变量在堆区
Day09 面向对象特性
封装
- 封装的好处:安全、保护隐私
- 属性的封装:对需要封装的属性设置访问权限;对外提供设置和读取的方法。
- 属性封装的原则是将属性隐藏起来,提供公共方法进行对其访问。
- 属性封装的目的:隐藏类的实现细节;可以在方法里加入逻辑控制;保证对象信息的完整新;便于修改,提高可维护性
权限修饰符:public、默认、protected、private
(类的权限修饰符只能是public或缺省,成员变量和成员方法四个都可以)
封装的练习题,代码如下:
public class Employee {
private String id;
private int age;
int salary;
private String name;
public Employee(String i,String n,int a,int s){
id=i;
name=n;
age=a;
salary=s;
}
public void getinfol(){
System.out.println("id:"+id+" name:"+name+" age:"+age+" salary:"+salary);
}
String getid(){
return id;
}
String getName(){
return name;
}
public int getAge(){
return age;
}
public int getSalary(){
return salary;
}
public void setid(String i){
id=i;
}
public void setName(String n){
name=n;
}
public void setAge(int a){
age=a;
}
public void setSalary(int s){
salary=s;
}
}
public class Demo {
public static void main(String[] args) {
//封装
Employee[] arr=new Employee[3];
arr[0]=new Employee("1","郑馨蕾",20,30);
arr[1]=new Employee("2","杨帆",22,60);
arr[2]=new Employee("3","齐金伟",21,70);
for (int i = 0; i < arr.length; i++) {
arr[i].getinfol();
}
}
this关键字
在类中
this指当前对象(不是当前类)
this.内容:区分局部变量和成员变量重名,其中想要访问成员变量就是this.属性名
this():调用本类的构造器,必须要在构造器里面的首行
在继承中
this调用哪个类的变量,就使用哪个类的变量
static—静态的
类在加载的时候,先加载所有的静态资源
再加载所有的普通资源
1.修饰成员变量
实例变量:属于对象的
类变量:属于类的 在成员变量上添加static
静态的属性,空间开辟在方法区内,并且只有一份,原因类只加载一次,所有对象操作该属性的时候,操作的都是方法区的同一个空间,以达到共享的目的
调用的时候要符合权限修饰符的范围
2.修饰成员方法
实例方法:属于对象的
类方法:属于类的 在成员方法上添加static
类名.方法 不依赖于对象
静态资源中只直接使用静态资源,不能直接使用非静态资源
static总结
用于属性:为了资源共享
用于方法:为了类名调用方便
final
1.修饰类;该类不被继承,String类就是被final修饰
2.修饰变量;若修饰成员变量,必须初始化,若修饰局部变量,可以不初始化,但是却使用不了
3.修饰方法;该方法不能被重写
继承
继承是子类继承父类的属性和行为,使得子类独享具有与父类相同的属性、相同的行为
继承的好处
- 提高代码的复用性
- 提高代码的扩展性
- 类与类之间产生了关系
继承之成员变量
不重名,访问的是父类的
重名,this.成员变量访问的是当前类的成员;super.成员变量访问的是父类的成员变量
继承之成员方法
不重复,访问该子类方法没有影响
重复,那么就是方法重写将父类的方法的覆盖
成员方法在调用的时候,看对象的实际对象
继承之构造器
由于构造器的名称必须和类名一致,所以子类是无法 继承父类构造器
构造器默认第一句话为super();调用父类无参构造器
java继承的特点:单继承
一个类只能由一个直接父类,但是一个类可以有多个子类,具有具有局限性(接口可以解决这个问题)。
任何类都有父类,没有显示写extends 默认是object
继承总结
属性看类,方法看对象
this是从本身到祖宗,super是父亲到祖宗
要注意类是否被加载到内存中了没有
继承代码练习如下:
public class Father {
public String name="Jack";
public int age;
public void function(){
System.out.println(this.name);
this.eat();
}
public void eat(){
System.out.println("Father is eating");
}
}
public class Son extends Father {
String name="rose";
public void method(){
System.out.println(this.name);
this.eat();
}
public void eat(){
System.out.println("Son is eating");
}
}
public class Demo {
public static void main(String[] args) {
Son son =new Son();
son.method();
son.function();
Father father =new Father();
father.function();
}
}
输出结果
rose
Son is eating
Jack
Son is eating
Jack
Father is eating
多态
前提:
- 父子类
- 必须有重写
- 父类引用指向子类对象
多态不能调用子类独有的内容,只能调父类的东西
上转下可能出现ClassCastException 类型转换异常
强转之前要做判断:instanceof 判断前后类型
实例化初始块
要写在类里面,每次实例化对象自动执行的一个代码块,要建立对象才运行
语法:{ }
特点:在构造器之前运行
如果有继承,运行顺序:父类实例初始化块->父类构造器->子类实例初始化块->子类构造器
类初始化块
在类加载的时候只执行一次
语法:static(修饰符) { }
如果有继承,运行的顺序:先加载父类的类初始化块,再执行子类的
总结这里的执行顺序父类初始化块->子类初始化块->父类实例初始化块->父类构造器->子类实例初始化块->子类构造器
构造器
IDEA快捷键:alt+fn+insert
构造器:可以无参构造也可以有参构造,方法名和类名必须要统一
构造器的运行时机:实例化一次调用一次
构造器是new的时候一起调用的
(任何一个类都会默认一个无参构造器,写了就会覆盖,所以写了有参构造一定要补充一个无参构造,最后构造器可以重载)
抽象类
- 使用abstract修饰类
- 抽象类可以有0-n个抽象方法或普通方法
- 这一代不能实现抽象类中的方法,那么就变成抽象类 ,让子孙后代来实现
- 抽象类不能实例化对象,所以都当作父类来使用
- 抽象类的构造器初始化子类对象的父类空间
Day14
接口
JDK1.8之前
- 接口中的所有成员变量默认为公有的静态常量
- 接口中的所有成员方法默认为公有的抽象方法
- 接口中没有构造器
- 没有初始化块
JDK1.8之后
- 默认方法和静态方法
特点:
- 接口不能实例化对象
- 只能作为父级
- 实现类实现父接口,并实现父接口中所有的抽象方法
java.lang.Comparable.CompareTo接口
自然排序,在类中实现该接口,根据程序员所定义的值比,是this和obj对比
返回值: 正数说明this大
负数说明this小
0说明一样大
Comparator接口
定制排序,在没有权限实现CompareTo接口时或者已经实现了CompareTo接口但不满足自己的要求,自己创建一个类并实现Comparator的方法
内部类
匿名内部类
语法:new 类、抽象类、接口(){这里面写实现的代码}
JDK1.8 Lambda表达式对匿名内部类简化
成员内部类
成员内部类的对象实例化,依赖于外部类的对象
内部类可以直接使用外部类的方法和变量
外部类以及外部其他类要使用内部类资源要建立内部类的对象再使用
静态成员类
因为是静态,不依赖于外部类
内部类可以直接使用外部类的静态资源,但是非静态资源要实例化对象
方法(局部)内部类
语法:【修饰符】class 类名{ }修饰符只能取abstract和final
内部类用外部类直接使用
当前局部可以实例化对象的形式访问,注意作用域
枚举
JDK1.5之前 通过自己写 参考单例设计模式
- 必须将构造器私有化
- 需要设置若干个共有的静态常量。如果是对象,一定要设置为final;类中如果有属性,那么不能提供set方法
代码练习,如下:
package Javase.study.practice.Day13;
public class JiJie {
public static void main(String[] args) {
Show_Month show_month=new Show_Month();
show_month.setMonth(Month.JAN);
Show_Month show_month1=new Show_Month();
show_month1.setMonth(Month.FBER);
System.out.println(show_month.getMonth().getNumber());
System.out.println(show_month1.getMonth().getNumber());
}
}
class Show_Month{
private Month month;
public Show_Month() {
}
public Month getMonth() {
return month;
}
public void setMonth(Month month) {
this.month = month;
}
}
class Month{
private int number;
public static final Month JAN=new Month(1);
public static final Month FBER=new Month(2);
public Month() {
}
private Month(int number){
this.number=number;
}
public int getNumber(){
return number;
}
}
JDK1.5之后
引入关键字enum
枚举类存在一个默认的父类Enum
方法:
- name(); 获取对象的名称
- toString(); 也是对象名称,但是允许枚举类重写
- ordinal(); 当前对象的位置
- static values(); 返回枚举类所有的常量对象
- static valueof(String name); 根据字符串的名称,返回枚举类的常量对象
代码练习,如下:
public class Test2 {
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
String str=sc.nextLine();
Week week0=Week.valueOf(str);
System.out.println(week0.getValue());
//JDK1.5之后
Week week=Week.FRIDAY;
System.out.println(week.getValue());
}
}
enum Week{
MONDAY("1"),
TUERDAY("2"),
WEDNESDAY("3"),
THURSDAY("4"),
FRIDAY("5") ;
private String value;
public String getValue() {
return value;
}
Week(String value) {
this.value = value;
}
}
输出结果:
单元测试 junit
@Test 注解完以后进行导包
@Before 每个Test之前运行
@After 每个Test之后运行
@BeforeClass在所有Test之前运行一次
@AfterClass在所有Test之后运行一次
缺点:
默认不能手动输入
学IO流的时候,关于相对路径有自己的特点
不能够启动线程
手动导入的
- new 目录(lib)
- junit-4.12.jar 有可能还要添加hamcrest-core-1.3.jar到lib里面
- add as library
包装类
装箱、拆箱,代码如下:
@Test
public void test1(){
byte b1=10;
//手动装箱
Byte b2=new Byte(b1);
Byte b3=new Byte("35");
//自动装箱
Byte b4=b1;
//手动拆箱
byte b5=b2.byteValue();
//自动拆箱
byte b6=b2;
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(b4);
System.out.println(b5);
System.out.println(b6);
}
包装类对比规则
- 如果在默认值的范围内的自动装箱,则相等
- 一旦自己手动装箱有new就不相等
- 如果不在默认值的范围内也不相等
- 如果和基本数据类型参与对比,包装类类型就会自动拆箱变为基本数据类型,所以只要值相等,那么就相等
Day16
异常
Throwable为顶层异常类
其中体系包括Error和Exception
两个常用的方法:
getMessage()得到异常的基本内容
printStacTrace()得到异常详细信息
常见异常
- 栈溢出异常 StackOverflowError
- 数组下标越界 ArrayIndexOutOfBoundsException
- 空指针异常 NullPoinException
- 类型转换异常 ClassCastException
- 类型不匹配 InpuMismatchException
- 数学操作异常 ArithmeticException
异常处理
抛出异常:throw new 异常();
声明异常:throws 异常
捕获异常:try catch finally
自定义异常 继承于java.lang.Exception或java.lang.RuntimeException
练习代码如下:
public class Demo1 {
public static void main(String[] args) throws LoginException {
Account account =new Account(1,23);
// account.CunMoney(-1);
account.CunMoney(20);
System.out.println(account.getMoney());
//account.QuMoney(-1);
//account.QuMoney(100);
account.QuMoney(10);
System.out.println(account.getMoney());
String name="sd";
String password="admin";
Login(name,password);
}
public static void Login(String name, String number) throws LoginException {
if (name == "admin" && number == "admin")
System.out.println("登录成功");
else
throw new LoginException("登录失败");
}
}
class Account{
private int number;
private int money;
public void CunMoney(int money){
if(money<0)
throw new IllegalArgumentException("存款金额有误,不能为负数");
else
this.money=money+this.money;
}
public void QuMoney (int money){
if(money<0)
throw new IllegalArgumentException("取款金额为负数");
else if(money>this.money)
throw new UnsupportedOperationException("取款金额不足,不支持当前操作");
else
this.money=this.money-money;
return;
}
public void setNumber(int number) {
this.number = number;
}
public void setMoney(int money) {
this.money = money;
}
public int getNumber() {
return number;
}
public int getMoney() {
return money;
}
public Account() {
}
public Account(int number, int money) {
this.number = number;
this.money = money;
}
}
class LoginException extends Exception{
public LoginException() {
}
public LoginException(String message) {
super(message);
}
}
字符串
字符串的方法
代码练习如下:
public class Demo2 {
public static void main(String[] args) {
String path="D:\\Program\\Java\\jdk1.8.0_181\\bin\\java.exe";
path=fun(path);
System.out.println(path);
String s="jack";
s=method(s);
System.out.println(s);
}
public static String method(String s){
String s1=s.substring(s.length()-1,s.length());
s1=s1.toUpperCase();
s=s.substring(0,s.length()-1);
s=s+s1;
return s;
}
public static String fun(String path){
int index=path.indexOf("java.exe");
String path1= path.substring(0,index);
String newpath=path1+"一定会上岸的Java.exe";
return newpath;
}
}
字符串拼接原则
1.常量+常量:结果是常量池
2.常量+变量或变量+变量:结果是在堆
3.拼接后调用intern(),结果在常量池中
4.concat方法拼接,结果在堆
常用的正则表达式
StringBuffer和StringBuider
【操作少量的数据】String:不可变字符序列
【多线程】StringBuffer:可变字符序列、效率低、线程安全
【单线程】StringBuilder(JDK1.5):可变字符序列、效率高、线程不安全
Date
//获取当前时间毫秒数 距离1970-1-1 0:0:0的毫秒差
Date date=new Date();
long l=date.getTime();
System.out.println(l);
long mill =System.currentTimeMillis();
System.out.println(mill==l);
//没有格式的日期
System.out.println(date);
//获取当前日期 带格式的
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String datTime=simpleDateFormat.format(date);
System.out.println(datTime);
线程
线程的创建
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread1 myThread1=new MyThread1();
myThread1.start();
MyThread2 myThread2=new MyThread2();
Thread thread=new Thread(myThread2,"Runnable创建的第一个线程");
thread.start();
//匿名内部类实现线程
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},"匿名内部类实现的第一个线程创建").start();
}
}
//实现runnable接口的线程创建
class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
//继承Thread类 创建线程
class MyThread1 extends Thread{
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName());
}
}
线程的常用方法:
- run():执行线程的具体操作
- start():启动线程
- sleep():暂停线程
- join():插队
解决线程安全问题,三种方式完成同步操作:
- 同步代码块
- 同步方法
- 锁机制
线程之间的练习,做包子和吃包子,类比操作系统同步互斥的伪代码
public class ThreadDemo2 {
public static void main(String[] args) {
Bao bao=new Bao();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10; i++) {
try {
bao.addBao();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"做包子").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <10; i++) {
try {
bao.divBao();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"吃包子").start();
}
}
class Bao{
boolean flag=false;
public synchronized void addBao() throws InterruptedException {
if(flag!=false)
this.wait();
else
this.flag=true;
System.out.println(flag+Thread.currentThread().getName());
this.notifyAll();
}
public synchronized void divBao() throws InterruptedException {
if(flag!=true)
this.wait();
else
this.flag=false;
System.out.println(flag+Thread.currentThread().getName());
this.notifyAll();
}
}
Thread和Runnable区别
- 适合多个相同的程序代码的线程去共享同一个资源
- 可以避免Java中的单继承的局限性
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立
- 线程池只能放入实现runnable或callable类线程,不能直接放入继承Thread的类
WAITING和TIMED_WATING区别
waiting更像是约定而Time_waiting有设置的时间
释放锁的操作
- 当前线程的同步方法、同步代码块执行结束
- 当前线程的同步方法、同步代码块中遇到break、return终止了该代码块,该方法继续执行
- 当前线程的同步方法、同步代码块中出现了未处理的Error或Exception,导致当前线程异常结束
- 当前线程的同步方法、同步代码块中执行了锁对象的wait()方法,当前线程被挂起,并释放锁
sleep()和wait()的区别
- sleep()不释放锁,wait()释放锁
- sleep()指定休眠时间,wait可以指定时间也可以无限等待直到notify或notifyall
- sleep()在Thread类中声明的静态方法,wait()方法在object类中声明
Day18
泛型
jdk1.5开始出现新特性,成为泛型;使用泛型可以限定集合或数组放什么数据类型,方法里面传递什么类型的参数。
public class T2 {
public static void main(String[] args) {
//语文老师
Student<String> student1=new Student<>("郑馨蕾","优秀");
//数学老师
Student<Double> student2=new Student<>("杨帆",82.5);
System.out.println(student1);
System.out.println(student2);
//
IDaoClass iDaoClass=new IDaoClass();
iDaoClass.add("齐金伟");
}
}
interface IDao<T>{
public void add(T name);
}
class IDaoClass implements IDao<String>{
@Override
public void add(String name) {
System.out.println(name+" 根据接口实例化对象使用泛型");
}
}
class Student<T>{
private String name;
private T score;
public String getName() {
return name;
}
public T getScore() {
return score;
}
public void setName(String name) {
this.name = name;
}
public void setScore(T score) {
this.score = score;
}
public Student() {
}
public Student(String name, T score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
泛型擦除
泛型在编译时出现,编译之后没有泛型,处理机制是通过类型擦除
通配符?
当我们声明一个方法时,不确定泛型的实际类型,我们就考虑使用通配符 比如建立一个Student<?>[] arr = new Student[长度];
集合
集合主要分为两大系列:collection和map。collection表示一组对象,map表示一组映射关系或键值对。
- List 有序的collection。用户可以根据元素的整数索引访问元素,并搜索列表中的元素
- Queue以FIFO的方式排序各个元素
- Set是一个不包括重复元素的collection。
迭代器
遍历获取集合中的所有元素,并不是所有的集合都能使用Iterator迭代器,使用前提条件是集合需要Iterator接口的子接口(map不能使用)
原理:hasnext()判断下一位是否还有元素,通过游标和长度,如果游标和长度值相等返回false
不要在使用Iterator迭代器进行迭代时,调用collection的remove()方法,否则会报异常java.util.ConcurrentModificationException,或出现不确定行为。【并发修改问题】
增强for循环
jdk1.5之后的简写方式,通过迭代器进行简化编写
//也可以看作是List类的遍历
public class Demo1 {
public static void main(String[] args) {
Collection<String> collection1=new ArrayList<>();
collection1.add("郑馨蕾");
collection1.add("杨帆");
collection1.add("齐金伟");
collection1.add("刘辉");
//迭代器运行,类似于数据结构里面的带头结点的链表
Iterator<String> iterator=collection1.iterator();
while (iterator.hasNext()){
String i=iterator.next();
System.out.println("迭代器:"+i);
}
//增强for循环
for (String item:collection1){
System.out.println("增强for循环:"+item);
}
}
}
List
List的特点
- List接口是collection接口的子接口
- List集合里面存储数据结构有序的,List集合可以有重复的元素
- List接口有很多实现类,List底层结构数组、链表等
List的遍历方式
- 普通for
- 增强for
- 迭代器
- ListIterator迭代器(很少人用,但是也算是一种方法),ListIterator是Iterator的子接口
List以及常用实现类ArrayList、LinkedList、Vector
List接口有很多实现类,常见的是ArrayList、LinkedList、Vector
(1)ArrayList
数据存储的结构是数组结构,元素增删慢,查找快。会有线程安全问题,效率高。
- 创建List集合,有三部分:Object数组,size,modCount版本
- 创建List集合之后,Object数组大小变成10
- 向数组添加数据超过了10,进行1.5倍大小扩容
(2)Vector
数据存储的结构是数组结构,解决了线程安全问题,效率低。加了synchronizaed。 - Vector对象有四部分:Object数组初始值为10,elementCount元素数量,capacityIncrement增量默认0,modCount版本
- 向数组添加数据超过了10,进行2倍大小扩容
(3)LinkedList
数据存储的结构是双向链表结构,增删快,查找慢。
-四个结构:size、first、last、modCount
Set以及常用实现类HashSet、TreeSet、LinkedHashSet
- set也是collection的子接口;
- set接口***不能重复,无序***的;
- set的遍历可以使用***迭代器和增强for***
- HashSet底层是HashMap,LinkedHashSet是HashSet子类,TreeSet底层是TreeMap使用红黑树
Map
Mao<K,V>接口 key - value,键值对存储方式
Map中的集合不能包含重复的键,值可以重复,每个键只能对应一个值
Map中的常用方法:
- 添加 put(K key,V value);
- 根据key获取对应value值 get(Object key);
- 移除 remove(Object key);
- 返回map集合所有key Set keySet();
- 返回map集合所有value values();
- 清空map集合 clear();
map的遍历方式归纳为两种:
public static void main(String[] args) {
Map<String,String> map=new LinkedHashMap<>();
map.put("18280101","郑馨蕾");
map.put("18280102","杨帆");
map.put("18280103","齐金伟");
map.put("18280104","刘辉");
System.out.println(map);
//第一种 获取map里面所有key,根据key获取value值
Set<String> allKeys = map.keySet();
for (String key:allKeys){
String value=map.get(key);
System.out.println(key+" "+value);
}
//第二种 获取map里面所有value,根据value获取key值(了解,用的不多)
Set<Map.Entry<String, String>> entries = map.entrySet();
for ( Map.Entry<String, String> entry:entries){
String key=entry.getKey();
String value=entry.getValue();
System.out.println(key+" "+value);
}
}
HashMap的底层结构:当达到负载因子的容量时,就会扩容
计算的位置相同,key相同,那么进行替换;如果key不相同,则进行链表存储。在jdk1.8之后,数组大小为64,链表为8则会转化为树形结构
加入的值如果进入putVal的哈希值相同的话,扩容以后重新计算hash值再赋值给数组
HashMap底层源码总结
(1)创建HashMap对象时候,初始化几个值,
- 主要:table代表数组默认null,负载因子默认0.75,边界值0
(2)第一次向HashMap添加元素 - 根据添加数据key计算hash值
- 判断当前table数组是否为空,第一次肯定是空,数组进行初始化
– 数组容量 16 ,临界值 12 - 根据数组初始长度和hash值得到数组某个位置,在位置添加元素(第一次加不存在重复问题)
(3)容量不超过临界值12时候,再次添加数据
- 根据添加数据key计算hash值
- 根据数组长度和hash值得到数组某个位置,在位置添加元素
– 判断数组这个位置上面是否存在元素,如果不存在,添加
– 如果位置存在元素,
— 判断位置元素key是否一样,如果key相同,替换,如果key不一样,链表存储
(4)容量超过临界值12,添加数据
- 根据添加数据key计算hash值
- 根据数组长度和hash值得到数组某个位置,在位置添加元素
– 判断数组这个位置上面是否存在元素,如果不存在,添加
– 如果位置存在元素,
— 判断位置元素key是否一样,如果key相同,替换,如果key不一样,链表存储
– 判断数组容量是否超过临界值,如果超过进行扩容
— 把数组大小2倍,临界值2倍
— 把数组元素重新编排
(5)在jdk1.8优化
- 如果数组容量64,链表节点8,把链表转换树形结构
Hashtable和HashMap的区别
Hashtable和HashMap都是哈希表。但是Hashtable是线程安全的,任何非null对象都可以用作键或值。HashMap是线程不安全的,并允许使用null值和null键
File
常用方法
public class FileDemo1 {
public static void main(String[] args) throws IOException {
// 文件路径名
// String pathname = "D:\\aaa.txt";
// File file1 = new File(pathname);
// 文件路径名
String pathname2 = "E:\\0224\\bbb.txt";
File file = new File(pathname2);
//1 查看是否存在文件
boolean exists = file.exists();
//System.out.println(exists);
//2 获取文件路径和文件名称
// System.out.println("文件构造路径:"+file.getPath());
// System.out.println("文件名称:"+file.getName());
//3 public boolean isDirectory()` :此File表示的是否为目录。
//- `public boolean isFile()` :此File表示的是否为文件。
// System.out.println(file.isDirectory());
// System.out.println(file.isFile());
//相对路径
// ./ 当前目录下
// ../ 上层目录 ../../
//- public boolean createNewFile()` :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
//- `public boolean delete()` :删除由此File表示的文件或目录。 只能删除空目录。
//- `public boolean mkdir()` :创建由此File表示的目录。单层目录
//- `public boolean mkdirs()` :创建由此File表示的目录,包括任何必需但不存在的父目录。 多层目录
File f = new File("E:\\aaa.txt");
// System.out.println(f.exists());
boolean newFile = f.createNewFile();
// System.out.println(newFile);
// System.out.println(f.exists());
File f1 = new File("E:\\atguigu0224");
// System.out.println(f1.exists());
boolean mkdir = f1.mkdir();
// System.out.println(mkdir);
// System.out.println(f1.exists());
File f2 = new File("E:\\wwww\\abcd");
boolean mkdir1 = f2.mkdir();
// System.out.println(mkdir1);
boolean mkdirs = f2.mkdirs();
// System.out.println(mkdirs);
boolean f1delete = f1.delete();
// System.out.println(f1delete);
boolean f2delete = f2.delete();
// System.out.println(f2delete);
File dir = new File("E:\\wwww");
//获取当前目录下的文件以及文件夹的名称。
String[] names = dir.list();
for(String name : names){
System.out.println(name);
}
//获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
File[] files = dir.listFiles();
for (File file1 : files) {
System.out.println(file1);
}
}
}
递归操作遍历
public class FileDemo2 {
public static void main(String[] args) throws IOException {
File file = new File("E:\\wwww");
listSubFiles(file);
}
//递归遍历所有目录
public static void listSubFiles(File dir) {
//判断
if(dir !=null && dir.isDirectory()) {
//获取dir里面内容
File[] files = dir.listFiles();
//files是否为空
if(files != null) {
//遍历
for(File file:files) {
//递归调研
listSubFiles(file);
}
}
}
System.out.println(dir);
}
}
Day20
IO流
重点是读操作
InputStream文件输入流和OutputStrea文件输出流(字节流)
public class InPutStreamDemo1 {
public static void main(String[] args) throws Exception {
//创建操作文件输入流对象
InputStream inputStream = new FileInputStream("E:\\0224\\b.txt");
//读取文件内容
int read = inputStream.read();
System.out.println((char) read);
//关闭
inputStream.close();
}
@Test
public void readFile01() throws Exception {
//创建操作文件输入流对象
InputStream inputStream = new FileInputStream("E:\\0224\\b.txt");
//定义变量
int b;
//循环判断读取
while((b = inputStream.read())!=-1) {
System.out.println((char)b);
}
//关闭
inputStream.close();
}
@Test
public void readFile02() throws Exception {
//创建操作文件输入流对象
InputStream inputStream = new FileInputStream("E:\\0224\\b.txt");
//定义变量
int len;
//字节数组
byte[] b = new byte[1024];
//循环读取
while((len = inputStream.read(b))!=-1) {
System.out.println(new String(b));
}
//关闭
inputStream.close();
}
}
OutputStrea文件输出流
```java
public class OutPutStreamDemo1 {
public static void main(String[] args) throws Exception {
//创建操作文件输出流对象
OutputStream outputStream = new FileOutputStream("E:\\0224\\atguigu.txt");
//OutputStream outputStream = new FileOutputStream(new File("E:\\0224\\atguigu.txt"));
//向文件写入内容
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
//关闭输出流
outputStream.close();
}
@Test
public void outFile01() throws Exception {
//创建操作文件输出流对象
OutputStream out = new FileOutputStream("E:\\0224\\a.txt");
//写内容
byte[] b = "尚硅谷".getBytes();
out.write(b);
//关闭
out.close();
}
@Test
public void outFile02() throws Exception {
//创建操作文件输出流对象
OutputStream out = new FileOutputStream("E:\\0224\\b.txt");
//写内容
byte[] b = "abcde".getBytes();
//write 第一个参数开始位置 索引
// 第二个参数 从开始位置几个字符
out.write(b,2,2);
//关闭
out.close();
}
//追加操作
@Test
public void outFile03() throws Exception {
//创建操作文件输出流对象
OutputStream out = new FileOutputStream("E:\\0224\\b.txt",true);
//写内容
byte[] b = "wqerty".getBytes();
//write 第一个参数开始位置 索引
// 第二个参数 从开始位置几个字符
//out.write(b,0,6);
out.write(b,2,2);
//关闭
out.close();
}
}
读取文件信息到另外一个文件中
```java
public class TestInputOutputStream {
public static void main(String[] args) throws Exception {
//E:\01.jpg
//1 创建输入流读取文件
InputStream in = new FileInputStream("E:\\01.jpg");
//2 创建输出流
OutputStream out = new FileOutputStream("E:\\0224\\001.jpg");
//3 流对接:把输入流内容放到输出流里面
int len;
byte[] b = new byte[1024];
while((len=in.read(b))!=-1) {
//把读到内容直接写到文件
out.write(b,0,len);
}
//4 关闭
out.close();
in.close();
}
}
字符流操作
public class ReaderDemo {
public static void main(String[] args) throws Exception {
Reader reader = new FileReader("E:\\0224\\b.txt");
//字符数组读取
char[] cbuf = new char[1024];
int len;
while((len=reader.read(cbuf))!=-1) {
System.out.println(new String(cbuf,0,len));
}
reader.close();
}
@Test
public void demo1() throws Exception {
// 使用文件名称创建流对象
Writer fw = new FileWriter("E:\\0224\\b1.txt");
// 字符串转换为字节数组
char[] chars = "尚硅谷".toCharArray();
// 写出字符数组
fw.write(chars); // 尚硅谷
// 关闭资源
fw.close();
}
}
缓冲流
public class TestBufferDemo {
//缓冲流实现
@Test
public void test02() throws Exception {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("E:\\01.mp4"));
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("F:\\01.mp4"));
// 读写数据
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
fis.close();
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("普通流复制时间:"+(end - start)+" 毫秒");
}
//基本流实现
@Test
public void test01() throws Exception {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
FileInputStream fis = new FileInputStream("E:\\01.mp4");
FileOutputStream fos = new FileOutputStream("F:\\01.mp4");
// 读写数据
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
fis.close();
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("普通流复制时间:"+(end - start)+" 毫秒");
}
}
数据流DataInputStream、DataOutputStream
如果要在程序中进行对java数据的操作,那么使用数据流
/**
* 演示数据流操作
*/
public class IoStreamDemo1 {
//写操作
public static void main(String[] args) throws Exception {
//定义写入不同类型值
String name = "巫师";
char gender = '男';
//创建写数据流,把普通流包起来
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("game.dat"));
//写入内容
dataOutputStream.writeUTF(name);
dataOutputStream.writeChar(gender);
//数据流关闭
dataOutputStream.close();
}
//读操作
@Test
public void readDataStream() throws Exception {
DataInputStream dis = new DataInputStream(new FileInputStream("game.dat"));
String name = dis.readUTF();
char gender = dis.readChar();
System.out.println(name+","+gender);
dis.close();
}
}
序列化和反序列化
序列化:通俗来讲是把对象转换字节,存储到文件中 ObjectOutputStream类,要进行序列化要实现Serializable的接口
反序列化:把文件存储对象字节转换为对象 ObjInputStrea类
最后两天
网络编程三要素
协议、IP地址、端口号
IP地址分法:第一种是IPV4和IPV6,第二种公网地址( 万维网使用)和 私有地址( 局域网使用)
TCP的代码模拟
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
Socket socket=new Socket("127.0.0.1",8888);
//写操作
OutputStream outputStream=socket.getOutputStream();
outputStream.write("welcome".getBytes());
//关闭
socket.shutdownOutput();
InputStream inputStream=socket.getInputStream();
byte[] data=new byte[1024];
int len;
StringBuilder stringBuilder=new StringBuilder();
while ((len=inputStream.read(data))!=-1)
stringBuilder.append(new String(data,0,len));
System.out.println("服务器端发送的数据是:"+stringBuilder.toString());
}
}
public class ServerDemo1 {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket=new ServerSocket(8888);
System.out.println("等待连接");
//监听888端口是否有请求
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接成功");
//接收客户端发来的数据
InputStream inputStream=socket.getInputStream();
byte data[]=new byte[1024];
int len;
StringBuilder stringBuilder=new StringBuilder();
while((len=inputStream.read(data))!=-1)
stringBuilder.append(new String(data,0,len));
System.out.println("客户端发送的消息是:"+stringBuilder.toString());
//发送数据到客户端
OutputStream outputStream=socket.getOutputStream();
outputStream.write("欢迎登录".getBytes());
outputStream.flush();
//关闭
socket.close();
serverSocket.close();
}
}
UDP
public class UdpSend {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
List<String> all = new ArrayList<>();
all.add("冲啊");
all.add("肝啊");
all.add("我敲啊");
InetAddress ip = InetAddress.getByName("127.0.0.1");
int port = 9999;
byte[] data=new byte[1024];
for (String s : all) {
data = s.getBytes();
DatagramPacket datagramPacket=new DatagramPacket(data,data.length,ip,port);
ds.send(datagramPacket);
}
ds.close();
}
}
public class UdpRecive {
public static void main(String[] args) throws Exception {
// 1、建立接收端的DatagramSocket,需要指定本端的监听端口号
DatagramSocket ds = new DatagramSocket(9999);
//一直监听数据
while(true){
// 2、建立数据包DatagramPacket
byte[] buffer = new byte[1024*64];
DatagramPacket dp = new DatagramPacket(buffer , buffer.length);
// 3、调用Socket的接收方法
ds.receive(dp);
//4、拆封数据
String str = new String(buffer,0,dp.getLength());
System.out.println(str);
}
}
}
反射
反射是
(1)java代码编译class文件,java里面提供类Class,代表字节码文件。
(2)通过Class获取字节码文件,操作类里面所有内容(构造、属性、方法等)
类的加载
当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,如果没有意外,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载。
哪些操作会导致类的初始化?
(1)运行主方法所在的类,要先完成类初始化,再执行main方法
(2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化
(3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化
(4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类
(5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化
哪些使用类的操作,但是不会导致类的初始化?
(1)使用某个类的静态的常量(static final)
(2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化,即只有声明静态成员的类才会初始化
(3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化
类加载器分类
第一类 虚拟机自带类加载
(1)引导类加载器 Bootstrap Classloader
- 加载rt.jar包里面的内容
(2)扩展类加载 Extension ClassLoader
- 它负责加载jre/lib/ext扩展库
(3)应用类加载器 Application Classloader
- 加载当前项目class文件
第二类 自定义类加载
/**
*
* 演示类加载器获取
*/
public class ClassLoaderDemo {
public static void main(String[] args) {
ClassLoader classLoader1 = ClassLoaderDemo.class.getClassLoader();
System.out.println(classLoader1); //AppClassLoader
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2); //ExtClassLoader
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println(classLoader3);
}
}
反射的操作
获取Class四种方式
(1)类名.class
(2)对象.getClass()
(3)Class.forName(包类路径)
(4)类加载方法loadClass
反射方式实例化
/**
* 反射方法演示
*/
public class ClassDemo3 {
public static void main(String[] args) throws Exception {
// new User(); 调用无参数构造
// new User("lucy",20); 调用有参数构造
//1 newInstance方法创建
Class<?> clazz1 = Class.forName("com.atguigu.refelect.User");
User user = (User)clazz1.newInstance();
System.out.println("第一种写法:"+user);
//2 获取有参数构造创建
//获取有参数构造
Constructor<?> constructor = clazz1.getDeclaredConstructor(String.class, int.class);
Object o = constructor.newInstance("lucy", 20);
System.out.println("第二种写法:"+o);
}
}
class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
反射操作属性
//反射操作属性
@Test
public void test01() throws Exception {
//获取Class
Class<?> clazz = Class.forName("com.atguigu.refelect.User");
//获取属性 age
Field field = clazz.getDeclaredField("age");
//设置操作属性可以进行访问-针对private
field.setAccessible(true);
//创建User实例化
Object stu = clazz.newInstance();
//设置属性值
field.set(stu,20); //setAge(20)
//输出值
Object value = field.get(stu); //getAge()
System.out.println("id = "+ value);
}
反射操作方法
//反射操作方法
@Test
public void test02() throws Exception {
//获取Class
Class<?> clazz = Class.forName("com.atguigu.refelect.User");
//获取操作方法 setName
Method method = clazz.getDeclaredMethod("setName", String.class);
//让方法执行
User user = (User)clazz.newInstance();
method.invoke(user,"mary");
System.out.println(user.getName());
}
Lambda表达式
Lambda使用函数式编程思想,只关注结果,不关注过程。
使用Lambda表达式只能简化代码编写,不能提高速度。
lambda使用特点
(1)lambda表达式主要简化接口的部分代码的,接口里面必须只能有一个普通方法
(2)把只有一个普通方法的接口,称为函数式接口,在函数式接口上面有一个标志,在接口上面有注解 @FunctionalInterface,函数式接口可以有default和static方法
(3)自定义函数式接口
public class Demo2 {
public static void main(String[] args) {
//实现Foo接口add方法
Foo foo = (int a,int b) -> {
System.out.println("lambda test...");
return a+b;
};
//调用
int add = foo.add(2, 3);
System.out.println(add);
int div = foo.div(4, 2);
int sub = Foo.sub(3, 1);
System.out.println(div);
System.out.println(sub);
}
}
//创建函数式接口
@FunctionalInterface
interface Foo {
//两个数相加
public int add(int a,int b);
//其他类型的方法
default int div(int x,int y) {
return x/y;
}
public static int sub(int x,int y) {
return x-y;
}
}
函数式接口类型
消费型接口
/**
* 演示函数式接口
*/
public class Demo4 {
//消费型
@Test
public void test01() {
Consumer<String> consumer = (t) -> {
System.out.println(t);
};
consumer.accept("mary");
}
@Test
public void test02() {
//创建list集合,向放数据,把list集合遍历
List<String> list = Arrays.asList("java","c","python","c++","VB","C#");
list.forEach( s-> { System.out.println(s); });
}
@Test
public void test03() {
Map<Integer, String> map = new HashMap<>();
map.put(1, "java");
map.put(2, "c");
map.put(3, "python");
map.put(4, "c++");
map.put(5, "VB");
map.put(6, "C#");
map.forEach( (k,v)-> { System.out.println(k+"::"+v); });
}
}
供给型接口
//供给型接口
@Test
public void test04() {
Supplier<String> supplier = () -> {
return "sad";
};
String value = supplier.get();
System.out.println(value);
}
函数型(功能型)接口
//函数型接口
@Test
public void test05() {
Function<String,String> function = (t) -> {
System.out.println(t);
return "atguigu";
};
String value = function.apply("lucymary");
System.out.println(value);
}
public class Demo5 {
public static void main(String[] args) {
//创建map集合,放数据 key 编号 value对象
Map<Integer,Employee> map = new HashMap<>();
map.put(1,new Employee(1,"lucy",8000));
map.put(2, new Employee(2, "李四", 9000));
map.put(3, new Employee(3, "王五", 10000));
//遍历map集合
map.forEach((k,v)-> {
System.out.println("key:"+k+" value:"+v);
});
//把map工资,如果工资小于10000,替换为10000
map.replaceAll((k,v)->{
//从v对象获取工资值,判断如果小于10000
if(v.getSalary()<10000) {
v.setSalary(10000);
}
return v;
});
map.forEach((k,v) -> System.out.println(k+"="+v));
}
}
class Employee{
private int id;
private String name;
private double salary;
public Employee(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
public Employee() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
}
断定型接口
//断定型接口
@Test
public void test01() {
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("java");
list.add("atguigu");
list.add("ok");
list.add("yes");
//遍历list集合
list.forEach(str->{ System.out.println(str); });
System.out.println();
//如果字符串长度小于5,删除这个字符串
list.removeIf(str->str.length()<5);
list.forEach(str->System.out.println(str));
}
Stream流
Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,负责存储数据,Stream流讲的是计算,负责处理数据!”
Stream 的操作三个步骤:
1- 创建 Stream:通过一个数据源(如:集合、数组),获取一个流
2- 中间操作:中间操作是个操作链,对数据源的数据进行n次处理,但是在终结操作前,并不会真正执行。
3- 终止操作:一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream。
/**
* 创建Stream流
*/
public class StreamDemo1 {
public static void main(String[] args) {
//1 通过集合创建
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream1 = list.stream();
//2 通过数组
int[] arr = {1,2,3,4,5};
IntStream stream2 = Arrays.stream(arr);
//3 Stream里面of方法
Stream<Integer> stream3 = Stream.of(1,2,3,4,5);
//4 创建无限流
Stream<Double> stream4 = Stream.generate(Math::random);
Stream<Integer> stream5 = Stream.iterate(1, num -> num+=2);
}
}
5、中间操作
/**
* 创建Stream流
*/
public class StreamDemo1 {
public static void main(String[] args) {
//1 通过集合创建
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> stream1 = list.stream();
//2 通过数组
int[] arr = {1,2,3,4,5};
IntStream stream2 = Arrays.stream(arr);
//3 Stream里面of方法
Stream<Integer> stream3 = Stream.of(1,2,3,4,5);
//4 创建无限流
Stream<Double> stream4 = Stream.generate(Math::random);
Stream<Integer> stream5 = Stream.iterate(1, num -> num+=2);
}
//中间操作 filter
@Test
public void test01() {
//创建Stream流
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
//中间操作
stream = stream.filter(t -> t % 2 == 0);
//终止操作,输出
stream.forEach(System.out::println);
}
@Test
public void test02(){
Stream.of(1,2,3,4,5,6)
.filter(t -> t%2==0)
.forEach(System.out::println);
}
@Test
public void test03(){
Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
.distinct()
.forEach(System.out::println);
}
@Test
public void test06(){
Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
.skip(5)
.forEach(System.out::println);
}
@Test
public void test05(){
Stream.of(1,2,2,3,3,4,4,5,2,3,4,5,6,7)
.distinct() //(1,2,3,4,5,6,7)
.filter(t -> t%2!=0) //(1,3,5,7)
.limit(3)
.forEach(System.out::println);
}
@Test
public void test04(){
Stream.of(1,2,3,4,5,6,2,2,3,3,4,4,5)
.limit(4)
.forEach(System.out::println);
}
@Test
public void test11(){
String[] arr = {"hello","world","java"};
Arrays.stream(arr)
.map(t->t.toUpperCase())
.forEach(System.out::println);
}
}
6、终止操作
public class StreamDemo2 {
@Test
public void test14(){
List<Integer> list = Stream.of(1,2,4,5,7,8)
.filter(t -> t%2==0)
.collect(Collectors.toList());
System.out.println(list);
}
@Test
public void test13(){
Optional<Integer> max = Stream.of(1,2,4,5,7,8)
.reduce((t1,t2) -> t1>t2?t1:t2);//BinaryOperator接口 T apply(T t1, T t2)
System.out.println(max);
}
@Test
public void test12(){
Integer reduce = Stream.of(1,2,4,5,7,8)
.reduce(0, (t1,t2) -> t1+t2);//BinaryOperator接口 T apply(T t1, T t2)
System.out.println(reduce);
}
@Test
public void test11(){
Optional<Integer> max = Stream.of(1,2,4,5,7,8)
.max((t1,t2) -> Integer.compare(t1, t2));
System.out.println(max.get());
}
@Test
public void test10(){
Optional<Integer> opt = Stream.of(1,2,4,5,7,8)
.filter(t -> t%3==0)
.findFirst();
System.out.println(opt);
}
@Test
public void test09(){
Optional<Integer> opt = Stream.of(1,2,3,4,5,7,9)
.filter(t -> t%3==0)
.findFirst();
System.out.println(opt.get());
}
@Test
public void test08(){
Optional<Integer> opt = Stream.of(1,3,5,7,9).findFirst();
System.out.println(opt.get());
}
@Test
public void test04(){
boolean result = Stream.of(1,3,4,7,9)
.anyMatch(t -> t%2==0);
System.out.println(result);
}
@Test
public void test03(){
boolean result = Stream.of(1,3,5,7,9)
.allMatch(t -> t%2!=0);
System.out.println(result);
}
@Test
public void test02(){
long count = Stream.of(1,2,3,4,5)
.count();
System.out.println("count = " + count);
}
}