JavaSE-常用类、Stream 流式计算
常用类
内置包装类
基本数据类型对应的包装类
-
byte Byte
-
short Short
-
int Integer
-
long Long
-
float Float
-
double Double
-
char Character
-
boolean Boolean
Integer
类结构
构造器声明:
Integer i = new Integer(12);
Integer i2 = new Integer("12"); //String--->Integer
-
构造器参数为int 类型时
-
构造器参数为String 类型时
常用属性:
Integer.MAX_VALUE //返回int类型的最大范围
Integer.MIN_VALUE //返回int类型的最小范围
自动拆装箱:
// 自动装箱
Integer i = 12; //int--->Integer,实际上是调用了Integer.valueOf(12);
// 自动拆箱
Integer i2 = new Integer(12);
int i3 = i2; //Integer--->int,实际上调用了i2.intValue();
缓冲数组:
public class Demo{
public static void main(String[] args){
Integer i = 12;
Integer i2 = 12;
System.out.println(i==i2); //true
System.out.println(i.equals(i2)); //true
Integer i3 = 129;
Integer i4 = 129;
System.out.println(i==i2); //false
System.out.println(i.equals(i2)); //true
/*
== 比较的左右两侧的数值:
数值在-128~127之间:比较的是就是数(在缓冲数组中的数)。
数值不在-128~127之间:底层就创建对象 ==比较的就是左右的地址值。
源码发现valueOf 具有缓冲范围
*/
}
}
常用方法:
public class Demo{
public static void main(String[] args){
Integer i = new Integer(12);
Integer i2 = new Integer(12);
int res = i.compareTo(i2); // 比较
System.out.println(i==i2); //=> false,原因地址指向不同
System.out.println(i.equals(i2)); //=> true,源码:return value==((Integer)obj).intValue();
System.out.println(res); //=> 0,源码:return (x<y)?-1:((x==y)?0:1);
int num = Integer.parseInt("12"); // String--->int
String num2 = i.toString(); // Integer--->String
System.out.println(num2); //=> "12"
}
}
String
特点
-
不能被继承。类被final 修饰
-
String底层就是char类型的数组
- 不可变:在地址不变的情况下不可以修改字符串的值。
定义String类型:
public class Main{
public static void main(String[] args){
// 定义String类型变量
String name = "haha";
String name2 = new String("haha");
String name2 = new String(new char[]{'h','a','h','a'}); // 底层就是给value数组赋值。
}
}
常用方法:
public class Main{
public static void main(String[] args){
// 定义String类型变量
String name = "haha";
String name2 = new String("haha");
String name3 = new String("hbha");
int num = name.length(); // 获取字符串长度
boolean bool = name.isEmpty(); // 判断字符串是否为空
char a = name.charAt(3); // 返回字符串对应下标的字符
boolean bool2 = name.equals(name2); // 判断字符串相等
int num2 = name2.compareTo(name3); // 获取两字符串的就近差值(Ascii 码的差值/字符长度的差值)
String newStr = name.substring(1,[endIndex]); // 截取字符串下标位到末尾[endIndex]的字符串
String newStr2 = name.concat(name2); // 拼接字符串
String newStr3 = name.replace('a','j'); // 字符替换
boolean bool3 = name.contains('a'); // 判断字符串是否包含字符、字符串
String name4 = new String("h-a-h-a");
String[] arr = name4.split('-'); // 分割字符串
String newStr4 = name.toUpperCase().toLowerCase(); // 大小写转换
String newStr5 = name.trim(); // 首尾去空
}
}
源码分析equals() 与 compareTo() 方法
String 内存空间说明
public class HelloWorld {
public static void main(String []args) {
String a = "haha";
String b = new String("haha");
String c = "ha" + "ha";
String e = "ha";
String d = e + "ha";
String f = new String("haha");
System.out.println(a==c); // true
System.out.println(a==d); // false
System.out.println(a==b); // false
System.out.println(b==c); // false
System.out.println(b==f); // false
}
}
-
给定字符的拼接,会进编译器的优化,直接拼接成完整的字符串,直接在方法区常量池中开辟空间,然后地址给了栈中的变量,不会在堆中开辟空间。并且常量池的特点是第一次如果没有就开辟空间,如果存在就不开辟。
-
使用new关键字创建的对象就会在堆中开辟空间。(值可以从常量池中取)
-
有变量参与运算的字符串拼接会在堆中开辟空间,通过反汇编得知有变量参与运算的字符串会实例化StringBuilder。
类型转换
String to char[]
public static void stringToChar(String str){
char[] str_char_arr = str.toCharArray();
}
源码:
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length); // 数组复制
return result;
}
char[] to String
public static void charToString(){
char[] chars = {'1','2','3','4','5','6'};
String str1 = new String(chars); //通过String构造函数
String str2 = String.valueOf(chars); //通过String类型转换,实际也是new String(char[])
}
char[] to List
public static void arrayToList(){
Character[] chars = {'1','2','3','4','5','6','7','8','9'};
//方式一
List<Character> list1 = Arrays.asList(chars); //通过Arrays的工具类
//方式二
List<Character> list2 = new ArrayList<>(); //通过Collections工具类
Collections.addAll(list2,chars);
}
String to List
//原理就是首先将String转换成String[]数组,再通过工具类转换为List
public static void stringToList (String str){
String str1 = "123456";
//方式一
List<String>list1 = Arrays.asList(str.split("")); //str.split()返回一个String[]数组
//方式二
List<String>list2 = new ArrayList<>();
Collections.addAll(list2, str.split(""));
}
List to String
public static void listToString(){
List<String> list = Arrays.asList("1","2","3","4");
String str = String.join("", list); //"1234"
}
List to Set to List
public static void listToSet(){
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>(list); //直接构造函数即可
}
public static void setToList(){
Set<String> set = new HashSet<>();
List<String> list = new ArrayList<>(set); //直接构造函数即可
}
String to Set to String
public static void stringToSet(){
String str = "12345";
String[] strs= str.split("");
//方式一
List<String> list1 = Arrays.asList(strs);
Set<String> set1 = new HashSet<>(list1);
//方式二
Set<String> set2 = new HashSet<>();
Collections.addAll(set2, strs);
}
public static void setToString(){
Set<String> set = new HashSet<>();
String.join("", set);
}
StringBuilder(JDK1.5)
特点
- 可变:由于在构建中一直返回的是当前的类对象所以在地址不变的情况下是可以修改字符串的值。
public class Demo{
public static void main(String[] args){
StringBuilder str = new StringBuilder("abc");
str.append("ttttttt");
str.append("vvvvvvvvvvvvvvvvv");
System.out.println(str);
}
}
-
StringBuilder 底层就是一个char类型的数组。
-
调用空构造器默认新建16个空元素的char类型数组。
-
执行流程:(源码分析)
- 执行new StringBuilder(“abc”) 返回19 位字符数组
// public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
// 1. 构建初始化数组(value:"abc"),返回长度为19的空字符数组。
// AbstractStringBuilder.java
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
// StringBuilder.java
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
// 2. 调用append方法,判断是否增容,调用getChars进行复制,并且保存内存空间使用计数
// AbstractStringBuilder.java
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); // 0+3
str.getChars(0, len, value, count);
count += len;
return this;
}
// StringBuilder.java
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 3. 调用ensureCapacityInternal判断是否决定增容
// AbstractStringBuilder.java
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
// 4. 根据形参将value复制到长度为19的数组中。(0,3,[null....*19],0)
// String.java
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
- 再调用 str.append(“ttttttt”);
// 1. 调用append方法,判断是否增容,调用getChars进行复制,并且保存内存空间使用计数
// AbstractStringBuilder.java
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); // 3+7
str.getChars(0, len, value, count);
count += len;
return this;
}
// StringBuilder.java
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 2. 根据形参将value复制到长度为19的数组中。(0,7,[a,b,c,null....*16],3)
// String.java
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
- 再调用 str.append(“vvvvvvvvvvvvvvvvv”);
// 1. 调用append方法,判断是否增容,调用getChars进行复制,并且保存内存空间使用计数
// AbstractStringBuilder.java
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); // 10 + 17
str.getChars(0, len, value, count);
count += len;
return this;
}
// StringBuilder.java
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 2. 调用ensureCapacityInternal 增容,返回一个长度位 newCapacity(minimumCapacity) 的字符数组
// AbstractStringBuilder.java
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) { 27 > 19 ? true
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; // (19<<1)+2=40
if (newCapacity - minCapacity < 0) { // 40-27<0?false
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity; //return 40;
}
// 3. 根据形参将value复制到长度为27的数组中。(0,17,[a,b,c,t,t,t,t,t,t,t,null....*...],10)
// String.java
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
常用方法
public class Main{
public static void main(String[] args){
StringBuilder str = new StringBuilder("abc");
// 增
str.append("def");
// 删
str.delete(0,2); // 删除[0,2)下标的字符
str.deleteCharAt(2); // 删除指定下标的字符
// 改
str.insert(1,','); // 指定下标前插入
str.replace(1,2,'hh'); // 在下标[1,2)位置上替换字符
str.setCharAt(3,"2"); // 替换指定位置字符
// 查
for(int i = 0; i< str.length(); i++){
char c = str.charAt(i);
}
String s = str.substring(2,4); // 截取[2,4)返回一个新的String类型数据,对StringBuilder无影响。
}
}
理解什么是可变字符串,什么是不可变字符串?
String:在地址不变的情况下不可以修改字符串的值。
StringBuilder、StringBuffer:在地址不变的情况下可以修改字符串的值。
判定不可变和可变的前提是地址不变。String为什么是不可变字符串?因为String类型的值在堆中发生改变就要重建索引。而StringBuilder不同,只有唯一的引用地址,变得只是引用地址中的属性。
所以也可以解释为什么?StringBuilder sb = new StringBuilder(); System.out.print(sb.append(“def”)==sb.append(“abc”)); // true
StringBuffer(JDK1.0)
功能类似于StringBuilder
JDK 1.5新增了一个StringBuilder类,与StringBuffer相似,构造方法和基本方法基本相同。不同的是StringBuffer考虑了线程安全问题,而StringBuilder没考虑,所以StringBuffer线程安全,StringBuilder线程不安全,因此StringBuilder性能略高,通常情况下,创建一个内容可变的字符串应该考虑使用StringBuilder
StringBuffer:JDK1.0 效率低 线程安全
StringBuilder:JDK1.5 效率高 线程不安全
Date(JDK1.0)
sql 包下的Date 继承 util 包下的 Date
import java.util.Date; // 年月日时分秒
import java.sql.Date; // 年月日
public class Main{
public static void main(String[] args){
Date date = new Date();
date.getTime(); // 获取时间戳
// util ---> sql
java.sql.Date date2 = new java.sql.Date(date.getTime()); // 返回 年-月-日 格式数据
// sql ---> util
Date date = date2
// String ---> java.util.Date
// 1. String to java.sql.Date
// 2. java.sql.Date to java.util.Date
java.sql.Date date3 = new java.sql.Date.valueOf("2021-5-28");
java.util.Date date4 = date3;
}
}
上面的代码字符串参数具有局限性,只能是xxxx-xx-xx 格式的参数否则报错:
所以引入日期格式化的类:DateFormat
https://blog.csdn.net/qq_40915081/article/details/80298176
https://www.cnblogs.com/zhujiabin/p/6168671.html?utm_source=itdadao&utm_medium=referral
拓展:System.currentTimeMills
获取时间戳的方法:
-
new Date().getTime(); 在不考虑时区时,使用此方法获取时间戳会有性能上的损耗因为需要实例化对象,但是在需要考虑时区问题时只能使用此方法获取时间戳。
-
System.currentTimeMillis(); 从源码 public static native long currentTimeMillis() 看这是一个调用非java代码的接口,其时间来源依赖为其做了时区的处理,因此获取时间戳,在不考虑时区的情况下,他是最优选择。
-
Calendar.getInstance().getTimeInMillis()
DateFormat
注意:DateFormat 是一个抽象类不能被实例化,所以需要实例化其子类 SimpleDateFormat。
public class Main{
public static void main(String[] args){
// 定义格式
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// String ---> Date
try{
Date date = df.parse("2021-5-28 14:01:31");
}catch(ParseException e){
e.printStackTrace();
}
// Date ---> String
String str = df.format(new Date());
}
}
Calendar(JDK1.1)
日历类Calender 是一个抽象类不能直接实例化,所以只能实例化其子类GregorianCalender。
public class Demo{
public static void main(String[] args){
// 实例化对象方法:两种
Calendar cal1 = new GregorianCalendar();
// Calendar cal2 = Calendar.getInstance()
// 常用方法 get(参入Calender中定义的常量)
cal1.get(Calendar.YEAR); // 获取年份需要+1900
cal1.get(Calendar.MONTH); // 获取月份,从0开始所以要+1
cal1.get(Calendar.DATE); // 获取日期
cal1.get(Calendar.DAY_OF_WEEK); // 获取星期
cal1.getActualMaximum(Calendar.DATE); // 获取这月的最大天数
cal1.getActualMinimum(Calendar.DATE); // 获取这月的最小天数
// set 设置日历
cal1.set(Calendar.YEAR,2020);
// setTime(Date date)
}
}
打印一个日历
import java.util.Calendar;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入查询的日期:");
if (sc.hasNextLine()) {
String str = sc.nextLine();
java.sql.Date date = java.sql.Date.valueOf(str);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
System.out.println("日\t一\t二\t三\t四\t五\t六\t");
// 获取输入日期当月的最大天数然后进行遍历
int maxDate = cal.getActualMaximum(Calendar.DATE);
// 获取当前天数后面加上*
int nowDate = cal.get(Calendar.DATE);
int count = 0;
// 获取对应日期对应的星期数,实际上就是每月1号前的空格
cal.set(Calendar.DATE, 1);
int num = cal.get(Calendar.DAY_OF_WEEK) - 1;
for (int i = 0; i < num; i++) {
System.out.print(" \t");
}
count += num;
for (int i = 1; i <= maxDate; i++) {
if (i == nowDate) {
System.out.print(i + "*\t");
} else {
System.out.print(i + "\t");
}
count++;
if (count % 7 == 0) {
System.out.println();
}
}
}
sc.close();
}
}
LocalDate、LocalTime、LocalDateTime(JKD1.8)
LocalDate(本地日期)LocalTime(本地时间)
- 方法一:now() 获取现在相关的日期、时间、日期时间。
public class Demo{
public static void main(String[] args){
LocalDate localDate = LocalDate.now(); // 2021-12-16
LocalTime localTime = LocalTime.now(); // 14:00:00.000
LocalDateTime localDateTime = LocalDateTime.now(); // 2021-12-16T14:00:00.000
}
}
- 方法二:of() 设置指定日期、时间、日期时间。
public class Demo{
public static void main(String[] args){
LocalDate of1 = LocalDate.of(2021,12,16);
LocalTime of2 = LocalTime.of(18,16,15);
LocalDateTime of3 = LocalDate.of(2021,12,16,18,16,15);
}
}
LocalDate(本地日期)LocalTime(本地时间)用得不是特别多。
LocalDateTime(本地日期时间)详解
获取:get
public class Demo{
public static void main(String[] args){
localDateTime.getYear(); // 获取年
localDateTime.getMonth(); // 获取月
localDateTime.getMonthValue(); // 获取月数值
localDateTime.getDayOfMonth(); // 获取天数
localDateTime.getDayOfWeek(); // 获取星期数
... getXXX();
}
}
设置:with
public class Demo{
public static void main(String[] args){
localDateTime.withYear(2022); // 设置年,会重新返回一个LocalDateTime 类型的数据
... withtXXX();
}
}
加减操作:plus/minus XXX()
类比,还是会重新返回LocalDateTime 类型的数据
DateTimeFormatter(JDK1.8)
在jdk 1.8 后出现了一个与DateFormat类似的类DateTimeFormatter
使用方法
public class Demo{
public static void main(String[] args){
// 实例化DateTimeFormatter,三种方式:
// 1. 预定义标准格式:ISO_LOCAL_DATE,ISO_LOCAL_TIME,ISO_LOCAL_DATE_TIME
DateTimeFormatter df1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
// 这个格式化类可以将LocalDateTime 转换成String
LocalDateTime localDateTime = LocalDateTime.now();
String str = df1.format(localDateTime); // 将当前日期时间打印出来
TemporalAccessor parseTime = df1.parse("2021-12-16T14:00:00.000"); // 将字符串打印成日期时间
// 2. 本地化相关格式:ofLocalizedDateTime([FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT]);
// FormatStyle.LONG:xxxx年xx月xx日 上/下午xx时xx分xx秒
// FormatStyle.MEDIUM:xxxx-xx-xx xx:xx:xx
// FormatStyle.SHORT:xx-xx-xx 上/下午xx:xx
DateTimeFormatter df2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
LocalDateTime localDateTime2 = LocalDateTime.now();
String str2 = df2.format(localDateTime2); // 根据填入的参数格式,将当前日期时间打印出来
TemporalAccessor parseTime2 = df2.parse(str2); // 根据填入的参数格式,将当前字符串打印成日期时间
3. 方式三:自定义格式:ofPattern("yyyy-MM-dd HH:mm:ss")
DateTimeFormatter df3 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime3 = LocalDateTime.now();
String str3 = df3.format(localDateTime3); // 根据填入的参数格式,将当前日期时间打印出来
TemporalAccessor parseTime3 = df3.parse(str3); // 根据填入的参数格式,将当前字符串打印成日期时间
}
}
Math
// 静态导入,可以将类名省略,然后import + static + 那个包下的哪个类下的所有内容(*)
// 静态导入后,本类中有同名的方法,优先调用本类的方法
import static java.lang.Math.*;
public class Main{
public static void main(String[] args){
System.out.println(Math.random()); //=> 随机数[0.0 1.0)
System.out.println("绝对值" + Math.abs(-9)); //=> 9
System.out.println("四舍五入" + Math.round(9.1)); //=> 9
System.out.println("向上取整" + Math.ceil(9.1)); //=> 10
System.out.println("向下取整" + Math.floor(9.1)); //=> 9
System.out.println("最大值" + Math.max(9,10)); //=> 10
System.out.println("最小值" + Math.min(9,10)); //=> 9
System.out.println("次幂" + Math.pow(2,2)); //=> 4
}
}
Random
public class Main{
public static void main(String[] args){
// 定义有参构造器,每次传入的参数只要是一样的那么产生的结果也是一样的。如要想要产生的随机数不一样我们就必须传入不一样的种子
Random r = new Random(System.currentTimeMillis());
// 定义无参构造器,就不用传种子
Random r2 = new Random();
r2.nextInt(10); // [0,10)的随机数
}
}
r2.nextDouble() 与Math.random() 间的关系:
枚举
定义枚举类的关键字是 enum
,所有的枚举都是隐性继承于Java.lang.Enum。枚举实际上还是一个类,而每个被类枚举的成员实质就是一个枚举类型的实例,他们默认都是public static final。可以直接通过枚举类直接使用。
// Gender.java
public enum Gender{
男,女;
}
// Demo.java
public class Demo{
public static void main(String[] args){
Demo demo = new Demo();
demo.setName('xiaoming');
demo.setAge(10);
demo.setSex(Gender.男);
System.out.println(demo.toString());
}
// 定义一个构造器
public Demo(){
}
private String name;
private int age;
private String sex;
// 重载
public Demo(String name,int age,Gender sex){
this.name = name;
this.age = age;
this.sex = sex;
}
// 私有属性的get和set
public String getName(){
return name;
}
public int getAge(){
return age;
}
public Gender getSex(){
return sex;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public void setSex(Gender sex){
this.sex = sex;
}
// 重写toString方法
@Override
public String toString(){
return "Student{" +
"age="+age+
", name='"+name+'\''+
", sex='"+sex+'\''+
'}';
}
}
Stream 流式计算
import java.util.Arrays;
import java.util.List;
class User {
private int age;
private String name;
private int id;
public User(int age, String name, int id) {
this.age = age;
this.name = name;
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", id=" + id +
'}';
}
}
public class Demo {
public static void main(String[] args) {
// 流式计算
List<User> users = Arrays.asList(new User(21, "a", 1), new User(22, "b", 2), new User(23, "c", 3),
new User(24, "d", 4), new User(25, "e", 5));
// 链式编程
users.stream()
.filter((u) -> {
return u.getId() % 2 == 0;
})
.filter((u) -> {
return u.getAge() > 23;
})
.map((u) -> {
// 传入一个类型数据,返回其他类型数据
return u.getName().toUpperCase();
})
.sorted((uu1, uu2) -> {
return uu2.compareTo(uu1);
})
.limit(1)
.forEach(System.out::println);
}
}