安装方法
参考How To Install Java with Apt-Get on Ubuntu 16.04
数据类型
final
关键字: 修饰类表示该类不能被继承,内部所有成员变量都是final的; 类的private
方法也会隐式地指定为final
方法。修饰变量时,如果是基本数据类型的变量,则其数值在初始化之后就不能更改; 如果是引用类型的变量,则初始化后不能被指向另一个对象。
object.getField() == 1
: 这种比较可能出现空指针异常
获取对象的类: object.getClass()
使用Optional
来减少空指针异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static Optional<List<String>> getA(boolean a) { if (a) { String [] results = {"a", "b", "c"}; return Optional.of(Arrays.asList(results)); } return Optional.empty(); }
public static void test() { Optional<List<String>> re = getA(true); re.isPresent(); re.ifPresent(result -> { console.log(result); }); }
|
Integer/Long/Double/Float/BigDecimal/AtomicInteger数字
- 千万不要用
Double/Float
来定义金额,因为经常会出现浮点数的精度问题,最好用大数类,例如BigDecimal/BigInteger
- AtomicInteger是一个线程安全整数类,同时只有一个线程可以对其操作
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
| a.longValue(); longValue.intValue(); 1L; String.valueOf(123); (byte)1; (int) myByte; (float) 1; new Long(12);
Math.ceil(9.2); Math.floor(9.2); Math.round(9.2); Math.abs(-0.9);
a == 0 ? false : true; a ? 1 : 0;
BigDecimal.ZERO; a.add(b); a.subtract(b); a.multiply(b); a.divide(b); a.compareTo(b); a.setScale(2); a.setScale(2, BigDecimal.ROUND_DOWN); a.setScale(2, BigDecimal.ROUND_UP);
|
String/StringBuffer字符串
与String
不同的是,StringBuffer
和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 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
| String a = "World"; String b = new String(array); String[] c = new String[] {"A", "B", "C"}; List<String> list = Arrays.asList(c); int len = b.length(); b.concat(a); b + a; System.out.printf("test %s", a); String.format("test %s", a); b.charAt(0); a.compareTo(Object o); a.compareToIgnoreCase(String str); a.startsWith(String prefix); a.endsWith(String suffix); a.indexOf(String str); a.contains(str); a.matches(".*?"); a.replaceAll(String regex, String replacement); String[] strArr = a.split(String regex); a.trim(); Integer.parseInt(str); Long.parseLong(str); String.join(",", new String[]{"foo", "bar"}) new BigDecimal("1.00");
str == null; "".equals(str); str.length <= 0; str.isEmpty();
StringBuffer c = new StringBuffer('Hello World'); c.append(String s); c.reverse(); c.capacity();
Date date = new Date(); System.out.println(date.toString());
char[] data = {'a', 'b', 'c'}; String str = new String(data);
String getStringRepresentation(ArrayList<Character> list) { StringBuilder builder = new StringBuilder(list.size()); for(Character ch: list) { builder.append(ch); } return builder.toString(); }
StringBuilder sb = new StringBuilder("content"); StringBuilder re = sb.reverse();
List list = new ArrayList(myCollections);
URLDecode.decode("test", "utf-8");
|
JSON
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| MyDto myDto = new Gson().fromJson(jsonString, MyDto.class); new JsonParser().parse(jsonString).getAsJsonObject().get("key1").toString();
try { JSONObject result = JSONObject.parseObject(string); return null != result; } catch (Exception e) { return false; }
import com.google.gson.Gson; Gson gson = new Gson(); String jsonString = gson.toJson(myObj); System.out.println(jsonString);
|
正则匹配
- java的正则匹配没有
findAll
的概念,需要自己在正则中加入类似()*
来实现多次匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Pattern p = Pattern.compile("(a.*?a)*", Pattern.CASE_INSENSITIVE|Pattern.MULTILINE); Matcher matcher = p.matcher("content");
while (matcher.find()) { System.out.println(matcher.group()); }
if (matcher.find() && matcher.groupCount() >= 1) { matches = new ArrayList(); for (int i = 1; i <= matcher.groupCount(); i++) { System.out.println(matcher.group(i)); } }
str.replaceAll(reg, "");
|
Array/Vector/Stack/Enumeration/Collections/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 39 40 41 42 43 44 45 46 47 48
| typeName[] arrayName; typeName arrayName[][] = new typeName[3][4]; double[] myList = new double[5]; List<String> names = Arrays.asList("xxx","yyy","zzz"); List<String> list1 = new ArrayList<>(); list1.addAll(list2); List<String> names = new ArrayList<String>() { { for (int i = 0; i< 10; i++) { add("add"+i); } } };
Arrays.asList("a", "b").size(); Arrays.asList("a", "b").contains("c");
for (double element: myList) {} for (int i = 0 ; i < myList.size(); i++) {}
Iterator<String> iterator = myList.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (item.equals("banana")) { iterator.remove(); } }
Stack<Integer> d = new Stack<integer>(); d.push(int a);
Enumeration<String> days; Vector<String> dayNames = new Vector<StringL>(); dayNames.add("Sunday"); days = dayNames.elements();
List<String> new = Lists.reverse(lists1);
List<E> subList(fromIndex, toIndex);
|
Set/HashSet/Stream集合
1 2
| String[] myList = new String[] { "a", "b" }; Set<String> mySet = new HashSet<String>(Arrays.asList(myList));
|
Stream API
- 是一系列对集合便利操作的工具集,类似
Laravel
里面的Collection
- Concat: 合并两个流:
Stream.concat(stream1, stream2)
- foreach: 遍历
- map: 映射,返回新的元素
- mapToInt/mapToDouble/mapToLong: 映射成指定的数字类型,映射完成后可以使用
summaryStatistics
方法得到统计的结果然后使用getMax/getMin/getSum/getAverage
等方法
- filter: 过滤,仅保留返回true的元素
- limit: 仅保留指定数量的元素
- sorted: 排序
- Collectors: 用于返回列表或字符串
1 2 3 4 5 6 7 8 9 10 11
| Record record = list.stream() .filter(record -> "name".equals(record.getName())) .findFirst() .orElse(null);
Record record = list.stream() .sorted(Comparator.comparingInt(Record::getTime)) .reversed() .collect(Collectors.toList());
|
Dictionary/Hashtable/Map/ConcurrentHashMap字典
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
|
HashMap<String, String> map = new HashMap<String, String>(); map.put("key", "value"); HashMap<String, String> map = new HashMap<String, String>() { { map.put("key1", "value1"); map.put("key2", "value2"); } };
map.containsKey(Object key); map.containsValue(Object value); map.equals(Object o); map.get(Object key); map.isEmpty(); map.put(K key, V value); map.remove(Object key); map.size(); map.values();
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println(entry.getKey(), entry.getValue); }
for (String key : map.keySet()) {String value = map.get(Key);} for (String value : map.values()) {}
String jsonStr = new Gson().toJson(myMap);
|
Queue队列
1 2 3 4 5 6 7
| Queue<String> queue = new LinkedList<String>(); queue.offer("a"); queue.add("a"); queue.poll(); queue.remove(); queue.element(); queue.peek();
|
时间处理
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
| Date date = new Date(); Long timestamp = date.getTime(); System.currentTimeMillis(); Date date = new Date(1234567890000); Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-05-01 00:00:00");
Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date zero = calendar.getTime();
TimeZone tz = TimeZone.getTimeZone("UTC"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); df.setTimeZone(tz); return df.format(new Date());
String dateStr = "Wed Sep 11 10:10:10 CST 2020"; Date date = (Date) df.parse(df);
date1.before(date2);
Calendar now = Calendar.getInstance() now.setTime(date); now.set(Calendar.DATE, now.get(Calendar.DATE) + 7);
|
类/对象/方法
- 类中可以使用
static {}
设置静态代码块,有助于优化程序性能,static块
可以放置于类中的任何地方,当类初次被加载的时候,会按照static块
的顺序来执行每个块,并且只会执行一次。
- 泛型类使用
<T>
来表示,? extends 类名
(上边界限定)表示只要继承某个类的都可以,? super 类名
(下边界限定)表示只要是某个类的父类都可以,单独的?
(无边界限定)表示没有任何限制
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
| public class Sample { static { long a = System.nanoTime(); testMethod(); } public Sample() {} public Sample(String param1) {} private static void testMethod() {} }
public class MyClass<T> { private T t; public MyClass(T t) { super(); this.t = t; } public T getT() {return t;} }
public Optinal<User> getUser(Long id) { if (null != id) {return Optinal.of(new User());} return Optinal.empty(); } Optional<user> userOp = getUser(1L); if (userOp.isPresent()) {...} else {...}
|
Function接口
1 2
| Function<Integer,Integer> test=i->i+1; test.apply(1);
|
异常处理
- 异常类的
getMessage()
和toString()
方法的区别,前者仅仅返回错误的信息,如果是空指针异常,一般返回的是null,而后者则会包含异常类的类型信息。建议如果是打印日志则使用toString()
方法,因为更详细,如果是给用户看的信息可以使用getMessage
方法仅展示给用户关键信息
文件/文件夹
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
| File file = new File(fileName); BufferedReader reader = null; reader = new BufferedReader(new FileReader(file)); String tempString = null; int line = 1; while ((tempString = reader.readLine()) != null) { System.out.println("line " + line + ": " + tempString); line++; } reader.close();
File file = new File(fileName); if (file.isFile() && file.exists()) { long fileLength = file.length(); byte[] fileContent = new byte[(int) fileLength]; FileInputStream in = new FileInputStream(file); in.read(fileContent); in.close(); String[] fileContentArr = new String(fileContent); }
File file = new File(path); if (!file.exists()) { file.createNewFile(); } FileWriter fw = new FileWriter(file.getAbsoluteFile()); BufferedWriter bw = new BufferedWriter(fw); bw.write(content); bw.close();
File dir = new File("/tmp/test/deep"); if (!dir.exists()) { dir.mkdirs(); }
|
Shell
1 2 3 4 5 6 7 8
| String cmd = "ls | grep abc"; String[] commands = {"/bin/sh", "-c", cmd}; Process process = Runtime.getRuntime().exec(commands); BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((s = stdInput.readline()) != null) { System.out.println(s); }
|
包
- JavaSE程序可以打包成Jar包(与平台无关的格式),JavaWeb程序可以打包成War包
1 2 3
| import java.io.*; java -jar myjar.jar; java -cp myjar.jar com.example.MainClass
|
线程/进程
ThreadLocal
: 保证线程安全(一次HTTP请求从开始到响应都是在一个线程内部,其他用户是在其他的线程里面)
1 2
| Thread current = THread.currentThread(); current.getId();
|
多线程
- 线程池只能放入实现
Runnable/callable
类的线程,不能放入继承Thread
的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MyThread extends Thread { @Override public void run() { System.out.println("线程执行"); } } new MyThread().start();
public class MyThread implements Runnable { public void run () { System.out.println("线程执行"); } }
MyThread mythread = new MyThread(); new Thread(mythread).start();
|
三方库
Jsch SSH连接工具
一个很老很久没有更新的工具,文档example比较全,但是只有这个工具用户量大一点,其他的用户量太少不敢用(Apache sshd则是因为文档太少,官方文档是针对它的server端)。执行shell
命令的时候建议使用ChannelExec
而不是ChannelShell
(因为后者的输出流里面类似于一个终端,会包含一些没用的命令提示符).
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
| Jsch jSch = new JSch(); jSch.addIdentity("name", prvKeyStr.getBytes, pubKeyStr.getBytes, keyPass.getBytes); Session session = jSch.getSession(username, ip, port); session.setConfig("StrictHostKeyChecking", "no"); session.setTimeout(10000); session.connect();
ChannelExec channelExec = (ChannelExec) this.session.openChannel("exec"); ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream error = new ByteArrayOutputStream(); channelExec.setCommand("ls"); channelExec.setOutputStream(out); channelExec.setErrStream(error); channelExec.connect(); int sleepCount = 0; do { try { Thread.sleep(100); } catch (InterruptedException e) { result.setExitCode(1); result.setStderr(SERVER_EXEC_ERROR + e.getMessage()); return result; } } while (!channelExec.isClosed() && sleepCount++ < 60); out.toString(); error.toString(); channelExec.getExitStatus();
|
TroubleShooting
**Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
**,这是在使用Gson
解析字符串时的报错,一般是因为字符串非标准Json
格式造成的
Unchecked assignment for ‘java.util.ArrayList’ to ‘java.util.ArrayList <…>: 可能是定义ArrayList
的时候没有使用<>
,可以用下面两种方法进行定义:
1 2
| ArrayList<MyList> myList = new ArrayList<>(); ArrayList<MyList> myList = new ArrayList<MyList>();
|
**com.alibaba.fastjson.JSONException: default constructor not found. **: fastjson
的坑,要求对应class必须有默认的构造函数(空参数)
fastjson出现$ref: $.data[2].indexs[0]: 又是fastjson
的坑,如果是需要序列化的对象中有对同一个对象的依赖,那么在JSON序列化中可能会将后续的对象转成这种字符串
扩展阅读