如题,这是我的jvav语法笔记

基本数据类型:

String语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

String.isEmpty() //String 是否为空 ,注意 : “ ” 不是空串!!

string.isBlank() //是否为空串 (更强)

string.strip(); //去除两边的空格;

string.stripLeading(); // 去除右括号

string.stripTrailing(); //去除左括号

string.trim() //去除空格(仅ascii的空格)

string.repeat(times); //String 重复 times 次

string.lines().forEach(System.out::println); //切分为 Stream 再对每一行进行操作(打印);

string.equals(string2) // 比较内容

string.split(sep) // 按照 sep 分割数组

string.substring( index1 , index2 ) // 截取子串 [index1,index2)

string.indexOf(sub) // 定位子串在原串中的位置

string.toUpperCase() //转大写 !!! 这里和c的语法不一样!!!

String msg = String.format(" abns : %d siabd %.1f" , max , avg); //格式化

String msg = "as" + "asdewf"; //一般写法


''' 相关的String Builder '''
StringBuilder sb = new StringBuilder();
sb.append(); //在末尾追加string / char
String st = sb.toString(); //最后再将sb这个char[]转化为String

''' 相关的String的拼接 join '''
String.join(",", columns) // 这里的 columns 可以是 hashmap.keySet / values

> Tips:如果你需要遍历整个字符串,通常更推荐先把字符串转成真正的字符数组:(如下)
1
2
3
4
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i]; // 数组访问通常比方法调用稍微快那么一点点
}

char语法

1
2
3
4
5

char ch = st.charAt(index);//从String 中获取char

if(ch == target) {};//比较char:

线性数据结构:

ArrayDeque(最频繁使用的)

⼀句话总结:需要 Stack 或 Queue 时,默认选ArrayDeque
使用的时候,为了方便,全部写成offerFirst /pollLast这样first 和 last 很清楚的格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

//ArrayDeque是Array + Deque(循环数组)(stack + deque)

import java.util.ArrayDeque;
import java.util.Deque;

// 创建一个存储整数的双端队列

ArrayDeque< > ad = new ArrayDeque<>();
//标清楚是Fist还是Last
// pop /push 和 poll/offer 都可以使用,同样标清楚first last
ad.pollFirst();
ad.pollLast();
ad.offerFirst();
ad.offerLast();

数组

核⼼:数组⻓度不可变,需要”变⻓”时要么 new 新数组,要么⽤ ArrayList
函数可以返回一个数组!

1
2
3
4
5
6
7
8
9
//⽣成新数组(反转)
static int[] reverse(int[] arr) {
int[] result = new int[arr.length];
for (int i = 0; i < arr.length ; i++) {
result[i] = arr[arr.length - 1 - i];
}
return result; // 返回新数组,原数组不变
}

ArrayList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.ArrayList; // 记得导包

public class Main {
public static void main(String[] args) {
// 创建一个存储 String 的 ArrayList
ArrayList<String> list = new ArrayList<>();

// 1. 添加元素
list.add("Java");
list.add("Python");

// 2. 获取元素
String language = list.get(0); // 获取 "Java"

// 3. 动态删除
list . remove(1); // 删除索引为 1 的元素
list . remove( Integer . valueOf ( 30 ) ) ; // 删除value == 30 的元素

// 4. 获取当前长度
int size = list.size();

// 5.第【1】个元素变成25
list.set( 1 , 25 );

//6.是否包含元素
list.contains(25);

list.get( index );

}
}

'''ArrayList<int> 不合法!泛型只能⽤包装类: Integer Double String

实践选择:不确定元素个数时先⽤ ArrayList 收集,最后按需转数组

ArrayList 需要删除元素的时候,需要反向遍历 !!避免 index 的改变而引起元素的跳过!!'''

StringBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
StringBuilder sb = new StringBuilder("整数:100 ");

char lastChar = sb.charAt(sb.length() - 1); // 获取最后一位字符

System.out.println(lastChar); // 输出: ' ' (空格)

sb.append(value); //添加

sb.insert(index , value); //插入

sb,delete(index1 , index2 ) ; //删除 [index1 , index2) 的元素

sb.deleteCharAt(index); //删除 [index]的元素;

sb.setCharAt(index , value); //set index 处的 value !!!!

sb.length();

sb.charAt(index);

sb.indexOf(substring value);

sb.toString();

Three Map

HashMap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//导包:
import java.util.HashMap;

//这里的 String 是 key 的类型 Integer 是value 的类型
HashMap<String , Integer> map = new HashMap<>();

'''
!! 注意
在 HashMap 的逻辑里,键(Key)是唯一的标识符,而值(Value)只是挂在键上的数据。
我们可以知道hashMap 查找key 是o(1) 但是查找 value 仍是全表查询,为o(n)
具有不对称性
'''

'''
!! 如果我需要“根据值快速查找”怎么办?
如果你发现你的程序频繁需要根据 Value 找 Key,或者频繁检查某个 Value 是否存在,且数据量巨大,那么单纯的 HashMap 就不是最优解了。业界常用的方案:双向映射(Bi-Map):手动维护两个 HashMap。Map<Key, Value> forwardMap<Value, Key> backward这样两边查询都是 O(1),代价是占用两倍内存,且每次 put 时要操作两个表。
'''

//put(k , v)插入键值对 , 而且这种插入是覆盖旧值的(当 put 已经有过的 key 时)
map.put("a" , 95);
map.put("a" , 97);
//则“a" -> 97

//get(k)获取键对应的value: 如果不存在则返回 null
map.get("a");

//getOrDefault() 为了避免null值的返回,可以设定默认值,这样如果在hashmap中找不到get的内容,就直接返回 默认值:
map.getOrDefault("b" , 0 ); //这里的 0 就是默认值
//词频统计:(经典)
freq.put(w, freq.getOrDefault(w, 0) + 1);

//containsKey(k) / containsValue(v) 判断hashmap中是否存在 该键/值。
map.containsKey("v");
map.containsValue(0);

//remove(k) 根据 key来删除整个键值对:
map.remove("a"); //删除 a -> 97 这个键值对

//size() 获取hashmap的大小:
map.size();

//keySet()获取整一串的 key;
map.keySet()
//(可以 for ( String x : map.keySet() ) 遍历整个hashMap的所有的key

//values()获取整一串的 value:
map.values()

'''
tip:keySet() 和 values() 排列的顺序是依据hashCode 的排列顺序来的(hashMap内部是数组 + 链表/红黑树的形式,所以插入的顺序和具体遍历时的顺序是不一样的
'''
//遍历⽤ entrySet() 最⾼效——避免keySet() + get() 两次查找。可以用 getKey() / getValue 取出每个键值对中具体的值:
for ( Map.Entry < String , Integer > e : map.entrySet( ) )
{
String key = e.getKey();
int val = e.getValue();
}

LinkedHashMap

1
2
//linkedhashmap 同时维护了一个一般的 hashmap 与双向链表
LinkedHashMap<String , Integer> lhm = new LinkedHashMap<>();

一般的 hashmap 的一个节点 包含的内容是 :
hashCode + key + value + next (hash crash 时指向下一个同hashcode 节点的 指针)
这个linkedhashmap 中一个节点:
hashcode + key + value + next + before + after
这个before 和 after 是根据数据实际的put的顺序修改的
在循环遍历的时候 ,是按照这个双向链表来进行的

默认选择HashMap即可

TreeMap

支持 hashmap的所有的操作, 也是实现了Map接口

不同的是 , treemap 是一颗二叉树 (基于红黑树), 不是数组 , treemap 是按照 key 的字典序排列的
所以treemap在实现 hashmap的查找功能的时候:
get(k) 的复杂度是 o ( log n )
containsKey(k)复杂度也是 o(log n)

1
2
3
4
5
6
7
8
9
10
11
TreeMap<String , Integer> tm = new  TreeMap<>();

//额外支持:
firstKey(); //最小键 o ( log n )

lastKey(); //最大键 o ( log n )

firstEntry(); //返回一个 Map.Entry(包含 Key 和 Value)。

lastEntry(); //返回最后一个键值对。

Three Set:

需要去重?
├── 不需排序 → HashSet
├── 需要排序 → TreeSet
└── 需要保持插⼊顺序 → LinkedHashSet

HashSet

hashSet 是只有 键 的hashmap ,去除了重复的key

1
2
3
4
5
6
7
8
9
10
11
12
HashSet<Student> set = new HashSet<>()

set.add(k); //添加键
set.contains(k); //查找键
set.remove(k); //删除键
set.size(); //大小

//如果已经有了key再次add会返回false不进行添加操作
//!求交集:
retainAll();
set1.retainAll(set2) ; 这时set1中就变成了set1 与 set2的交集

TreeSet

none

TreeSet

1
2
3
4
5
TreeSet<Integer> ts = new TreeSet<>();
ts.add(k);
first() ; //最小的
last(); //字典序最大的

输入输出/文件读入写入:

个人最常用的三个:

1
2
3
4
5
6
7
8
9
//读入输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//读入文件
BufferedReader br = Files.newBufferedReader(Paths.get(path(具体给出的路径)));
//或者有一些需要追加/新建的,就要用standardopenoption
BufferedReader br = Files.newBufferedReader(Paths.get(path(具体给出的路径)),StandardOpenOption.CREATE,StandardOpenOption.APPEND);
//写入文件
BufferedWriter br = Files.newBufferedWriter(Paths.get(path(具体给出的路径)));

之前的笔记:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//刚⼊⻔记这三组就够:
// ── 1.
//读⽂件(按⾏)
//────────────────────────
try (BufferedReader br = new BufferedReader(new FileReader("in.txt"))) {
String line;
while ((line = br.readLine()) != null) {
process(line);
}
}
// ── 2.
//写⽂件(按⾏)
// ────────────────────────
try (BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"))) {
bw.write("hello");
bw.newLine();
}
// ── 3.
//控制台交互
// ────────────────────────────
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.printf("n = %d%n", n);

//以下的方法都是从输入中读取的:

import java.io.*;!!!!!
//输入两种方式:
1.Scanner
Scanner sc = new Scanner(System.in);
String st = sc.next(); // string input
int num = sc.nextInt(); // int input
//用完要关掉:
sc.close();

2.BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input = br.readLine();
'''在 Java 中,凡是涉及到 readLine() 的操作,编译器都会强制要求你处理可能发生的 IOException。
最简单的修正方法:
这个需要在main的方法后面加一个throws IOException
报错信息大概长这样:
unreported exception java.io.IOException; must be caught or declared to be thrown'''

try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) { // 按⾏读,读到null为⽌
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}

//铁律:读⽂本⽂件永远⽤ BufferedReader 包装 FileReader







//以下的方法都是从文件中读取的:


//文件读取:

//对于给定路径的文件 逐行读取 以及 一次性读取

//对于给定path,读取path所指的文件
BufferedReader br = Files.newBufferedReader(Paths.get(path));
String line = br.readLine();

//用一个List<String> 一次性装下所有的行
List<String> lines = readAllLines(path);




//文件写入:

//对于给定路径的文件和已有的list ,将list中的每一行 逐行写入文件中 以及 文件不存在->新建文件 以及 追加模式
//对于目标的文件,逐行写入 已有的List<String>中的每一行, 覆盖式 的
BufferedWriter bw = Files.newBufferedWriter(Paths.get(path))
bw.write(line);
bw.write("\n");

//对于目标文件,在最后追加一行
BufferedWriter bw = Files.newBufferedWriter(Paths.get(path) , StandardOpenOption.CREATE //如果没找到目标的文件就创建(create), StandardOpenOption.APPEND//已有文件追加一行 );
//StandardOpenOption表示选择开启那些开关 ,这样就可以append而不是默认的追加,而且找不到文件也可以继续创建
br.write(line);




//跨文件写入:

//对于给定的src 和 dst 将 src 中的内容写入 dst 中:
BufferedReader br = Files.newBufferedReader(Paths.get(src)));
BufferedWriter bw = Files.newBufferedWriter(Paths.get(dst)));

String line = br.readLine();
bw.write(line); // if line != null;


'''
tips:
有时候写入 bw.newLine();不好用
就用 bw.write("\n");
'''

有关追加/覆盖更为详细的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// BufferedWriter  覆盖
try ( BufferedWriter bw = new BufferedWriter ( new FIleWriter ( " 写入的文件名" ) ) ) {
bw.write ( " ");// 写入
bw.newLine(); //下一行
}

// PrintWriter // 覆盖
try (PrintWriter pw = new PrintWriter ( " 写入文件名" ) ) {
pw.println( " " ); // 写入
pw.printf(" %d " , 123 ) ; // 写入
}

// Files 覆盖的 !!
Files.write( Path,get( " 写入文件名 " ) , Arrays.asList( " " , " " ) ) ;
//Arrays.asList("A", "B")这是在准备“货物”。Files.write 的这个重载版本要求传入一个Iterable(通常是 List)。

// 第二个参数不写,或者写 false,就是覆盖
FileWriter fw = new FileWriter("test.txt", false);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(fw);

// 第二个参数传 true,就是追加
FileWriter fw = new FileWriter("test.txt", true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(fw);

追加
FileWriter fw = new FileWriter( " " , true);

//if 存在 -》append else : create

// 核心语法:在路径和数据之后,列出 OpenOption
Files.write(
path,
Arrays.asList("新的一条日志内容"),
StandardOpenOption.CREATE, // 文件不存在就建一个
StandardOpenOption.APPEND // 文件存在就在末尾接着写
);

//推荐使用的读入方式:
try( BufferedReader br = new BufferedReader ( new FileReader ( " .txt") ) ) {
operate // 自动 close !!
}
//多种方式写入的话 用;隔开:
try( BufferedReader br = …… ;
BufferedWriter bw = …… ){}

files文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

import java.nio.file.*;

//读所有的行 -> list<String> !!!!最常用的 !!!
List<String> lines = Files.readAllLines( Paths.get("data.txt") );

//如果你想用 NIO 的方式开启一个 BufferedReader,应该使用 Files.newBufferedReader:
// 读取整个文件 -> 一个String
String content = Files.readString( Paths.get( " 文件名" ));

//读大文件
try ( Stream < String > stream = Files.lines( Paths.get(" 文件名 ") ) ) {
stream .filter ( l -> l.contains( " 筛选的需要包含的内容") ) .forEach(System.out :: println ); // 对于每个筛选出来的line进行输出 。
}//这里的stream 是输入的流

sort:

1
2
Collections.sort(result);//注意这里是将result本身转变了!!
return result;

异常:

try - catch 捕获异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

//catch(异常的类别 e) 表示将 e
public class ExceptionObjectDemo {
public static void main(String[] args) {
try {
String str = null;
System.out.println(str.length()); // 这里会抛出 NullPointerException

} catch (NullPointerException e) {
// e 是 NullPointerException 类型的引用变量
// 指向JVM创建的异常对象

System.out.println("e 的类型: " + e.getClass().getName());
System.out.println("e 的字符串表示: " + e); // 调用 e.toString()
System.out.println("e 的哈希码: " + System.identityHashCode(e));
}
}
}

try {}
catch ( err1 ){}
catch (err2 e) {}

'''常见异常:
FileNotFoundException
IOException
EOFException到达流末尾
UnsupportedEncodingException编码不⽀持// Mac/Linux 默认UTF-8 Windows 默认 GBK/GB231
SecurityException权限不⾜

对于不同操作系统的文件传输:明确规定编码的类型!!!!
铁律:跨平台代码必须指定编码
import java.nio.charset.StandardCharsets;

new InputStreamReader ( new FileInputStream ( " " ) , StandardCharsets.UTF_*);
'''


函数:(lambda)

private \ static \ public 访问修饰符 -> 封装
通过 private 隐藏属性,再提供 public 的方法来修改,你就可以在方法里加上校验逻辑。
无返回值:

1
2
3
static void printLine(String msg) {
System.out.println(">>> " + msg);
}

值传递(Pass by Value):Java 永远传递值的副本,函数内修改形参不影响实参

返回函数的函数(高阶函数)

1
2
3
4
5
6
7
// 修饰符      返回类型                  方法名      参数
public Function<Integer, Integer> createAdder(int increment){
return (Integer x ) -> x + increment;
}
Function<Integer , Integer> addFive = createAdder(5);
//createAdder(5)调用之后返回Function<Integer , Integer> 相当于赋值给addFive
//addFive是一个lambda 表示的函数,接受Integer 返回Integer(x + 5)

抽象为⾼阶函数 sum
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
term :函数参数,对每项求值
next :函数参数,计算下⼀项的位置

⽤ sum 重写三个过程
(define (sum-integers a b)
(sum (lambda (x) x)
a
(lambda (x) (+ x 1))
b))
(define (sum-cubes a b)
(sum cube
a
(lambda (x) (+ x 1))
b))
(define (sum-pi a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 2))))
a
(lambda (x) (+ x 4))
b))

如果你已经给一个动作起好了名字(比如 define (cube x) (* x x x)),你就可以直接用这个名字。

如果你还没给动作起名字,或者这个动作很简单、只用一次,你就用 lambda 现写一个“匿名函数”。

在 Java 的 Lambda 表达式(list -> …)中,如果逻辑超过一行,你需要使用大括号 {} 并显式使用 return 关键字。