很久没写过java了,此前很长一段时间里都写python,本文主要收集一些看起来和python不一样的地方。 够用就行 。
本篇笔记 不包含 面向对象的public/private/abstract/interface...等内容。
Table of Contents
基本数据类型
🔗 [Java 基本数据类型 | 菜鸟教程] https://www.runoob.com/java/java-basic-datatypes.html
8种基本数据类型:preview
类型转换
String转int, char, float, double...使用各自类型的 Double.parseDouble("1.114514") , Integer.parseInt("114514") , ... 抛出异常 NumberFormatException ,但 并不会不强制要求 catch Exception .
int, char, float, double...转String,统一使用 String.valueOf(xxx) ,所有类型都能填。
浮点数
double和float
有double和float的区分,且double的精度比float高
有关整数除法,小数除法,精度
有关整数除法,小数除法,精度
BigDecimal
首先是一段代码,试图在Java中用常规方法(Math, double)计算
如果引入一个很接近0的浮点数
但是我们注意到,在Java里面:
Float.MIN_VALUE = 1.4E-45
Double.MIN_VALUE = 4.9E-324
要想让结果逼近这两个更接近0的
Float.MIN_VALUE:
1.4E-45
Double.MIN_VALUE:
4.9E-324
用BigDecimal表示的gap:
1.7553650307552786834104640147489451426656313623012118352431838480274762801296239457483173231413486781454011184934233429206549379602764003089659139201681160454698974951744912285242105866207397328418704462027542366370688231103014415864621544859026041684045617816891111892125607087809393386227459297916158037460536929334574704E-324
用BigDecimal表示的Float.MIN_VALUE:
1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125E-45
用BigDecimal表示的Double.MIN_VALUE:
4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625E-324
说明gap < Float.MIN_VALUE:
-1
说明gap < Double.MIN_VALUE:
-1
随机数
🔗 [How do I generate random integers within a specific range in Java? - Stack Overflow] https://stackoverflow.com/questions/363681/how-do-i-generate-random-integers-within-a-specific-range-in-java
下面的程序会生成100个[0, 10]之间的整数和1000个[0, 11)之间的double,然后打印生成的最大/最小数据。
结果:
(Integer) min: 0, max: 10
(Double) min: 0.033906, max: 10.997501
ThreadLocalRandom.current().nextDouble(0, 11) 这玩意真的能生成出 0 吗?它生成0的概率是多少(这里假设是ThreadLocalRandom真随机,不然就没法估算了)?待续。
String的修改和复制
和Python一样,Java里面的String也是 immutable ,所以涉及到String的操作无需担心任何“浅拷贝”、“对象引用”。
并且要注意, new String() 的写法是完全多余的,任何时候都没有必要这么写。参考1,参考2(stackoverflow).
接下来是有关String内容的修改,直接写类似这样的操作: str[2]='K' 当然是不行的:
应该这么做:
另外,无论是在python还是javascript,类似 str[2]='K' 的操作都是无效的。python会报错:“TypeError: 'str' object does not support item assignment”,而javascript虽然不会报错,但不会有任何效果。
有关String的地址
有关String的地址
首先我们知道,Java里面是不能用 == 来比较字符串内容是否相同的,要用 .equal() .
但是下面的代码仍然会返回2个true:
我们还可以写:
但是从这里开始就不能用 == 判断了:
或者这样写也不能用 == 判断:
这是因为我们分别创建了String Literal和String Object:
进一步了解String.intern():
参考这里:🔗 [java的string存放位置的疑惑 - SegmentFault 思否] https://segmentfault.com/q/1010000009341279
next()和nextline()
输入数据,特别注意next()和nextline()的区别:
把next()改为nextline():
static方法
static方法
假设我现在只想写一个简单纯粹的function sqrt() ,返回开根号的结果,那么我可以写:
代码1:
也可以写:
运行结果都是一样的。
但是,在本程序的场景下仍然建议使用 static double sqrt() ,这是因为:程序只会生成一个static Object,不会每次都生成一个新的Object占用空间。
arr[]和ArrayList
如果使用场景比较简单(不要求兼容性/拓展性/性能),绝大多数场景都可以使用 for循环+排序+额外存储变量 来解决。
从python过渡:使用Object
(这部分内容是后面补充的,但写在最前面)
python的list是可以添加各种类型的数据的,java也可以这样做:
创建和打印
array和arraylist的区别:array本质上是静态的,类似C语言的数组array;arraylist类似python的list,可以动态调整
是否可以修改
默认初始化数值
访问元素/成员
array直接使用数组下标访问(但不能像python那样使用arr[-1]),ArrayList使用 .get(index) 来访问。
添加和移除
仅对ArrayList有效。讨论这些用法:
- append value at the end
- remove item by index
- remove item by value(fist occurance)
- remove all items by value
相互转换
arr[]转arrayList: 比想像中要复杂,没有什么特别简单的转换方法,都要稍微绕一下,多套几层
arrayList转arr[]: 通过 .toArray() 的方法转换只能得到 Object[] ,所以简单场景下还是还是手写循环来的快。
arr[]转arrayList:
arrayList转arr[]:
clone()是浅拷贝
类比于python的copy()和deepcopy(),Java里面也有类似的效果,
但这并不意味着java里面的clone()非常好用。 各种正规教科书/问答网站里都不推荐使用clone(),而是推荐自己手写。目前可以把clone()看作是python里的copy(),很多时候并不如deepcopy()那样好用,但好像java也不提供什么简单易用的deepcopy()...ArrayList也有相同结论:
参数传递
参数传递,首先是2个基本类型的参数传递:
int
String
arr[]和ArrayList:
排序
自带的排序算法sort()
Arrays.sort()和Collections.sort()分别提供了对 数组 和 ArrayList 的排序:
max()和min()
最大值max()和最小值min():
对ArrayList而言相对比较简单,只需要使用Collections.max()和Collextions.min()即可:
而数组就没有那么一步到位的方法了,目前看来只能用一些Java 8 以后的方法了:
搜索
搜索
没有什么特别好的方法,要注意 Arrays.binarySearch 非常难用,一般来说没有什么出场机会。
异常处理
由于Java在编译的时候会强制检查异常处理,所以这部分内容也算是必修项,绕不开的。
不同的try代码
下面的代码统一使用了 System.err.println() 来打印错误日志。
example 1(最常见):
example 2:
类似 try(xxxxxx) { } catch { } 这样的语句
example 3:
对整个方法try catch调用
不同的catch代码
列举常见的几种catch代码,需要注意的是 throw new RuntimeException("xxxxxxx") 会中断当前程序。
文件IO
简单的读写
暂时不考虑任何性能差异,这里使用了3个最容易学的File IO方法:
Scanner读,PrintWriter覆盖写,FileWriter追加写;
Scanner可以用nextLine()逐行读,也可以用nextInt(), nextFloat()等读法,和控制台输入的那个Scanner用法一致;
PrintWriter只能覆盖写;
FileWriter可以覆盖写,也可以追加写。
下面的代码让程序逐行读取一个文件 read.txt ,使用字符串保存每行的内容,然后原封不动写到一个新文件 write.txt 里面(此外还有追加写到 append.txt 里面):
异常处理
此外还要特别注意对异常处理的一些细节。注意下面的代码是有问题的:
程序一开始设定了 Scanner sc = null ,但捕获错误时仅仅使用了System.err.println(),所以程序还会继续运行,运行到sc.close()的时候会抛出一个新的错误。
应该这么改:
或者继续使用 System.err.println() ,但最后要检查Scanner是否为 null :
HashSet和HashMap
选这两个数据结构出来学习的原因是它们分别(近似的)对应python的set和dictionary
HashSet和HashMap是否会保留插入数据的顺序
两者都不会。
HashSet的基本用法
就像python的set那样
HashSet的常见方法有:
add:添加
remove:去除(可以去掉并不存在的元素而不引发报错)
contains:检查是否存在
HashSet里面的元素不允许重复,但:
你仍然可以试图向HashSet里面添加(add)重复元素(不会报错)
你仍然可以试图从HashSet里面移除(remove)一个不存在的元素(不会报错)
example:
初始化一个HashSet,并向里面丢入一堆东西:
用HashSet去除重复元素
和python去掉list重复元素的思路类似:
python:先转为set,再转回list
java:先转换为HashSet,再转回去
HashMap的基本用法
就像python的dictionary那样
HashMap:
(和HashTable的区别这里暂时不讨论了)
常见方法有:
put:放入
get:拿取
containsKey:检查key是否存在
keySet:列出所有keys
values:列出所有values
使用 put() 的时候有可能做到2个动作:1,添加新的key-value(如果它没有存在于HashMap)2,基于已有的key,更新现有key-value的value