1.好用的集合工厂方法
- Collection.of()
这些集合的of方法让我们代码变得简单,当我们只想展示我们想要展示的列表或者东西不是很多的场景中使用,这些api都是不可变的,我们知道集合工具类已经帮我们提供了转换成不可变的集合的方法unmodifiableXXX,为什么我们还需要List.of?因为它总是会copy原来的list到新的list,它不是很有效率,
1 2 3 4 5 6 7 8
| @Test public void testCollectionOf() { List<String> names = List.of("zs", "ls", "ww"); Set<String> of = Set.of("zl", "zq"); Map<String, Integer> users = Map.of("zs", 23, "ls", 24); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public void testList() { ArrayList<String> nameList = new ArrayList<>() {{ add("zs"); add("ls"); add("ww"); }}; List<String> unmodifiableList = Collections.unmodifiableList(nameList); List<String> names = List.of("zs", "ls", "ww"); }
|
- Stream.toList()
帮我们返回一个不可变的list,但它绝对不是collect(Collectors.toList())的替换,它有比collect(Collectors.toList())更好的优化,默认返回一个不可变的list,而前者返回的是一个arraylist
1 2 3 4 5 6 7 8 9
| @Test @SneakyThrows public void testList() { List<String> names = List.of("zs", "ls", "ww"); List<String> collectList = names.stream().collect(Collectors.toList()); collectList.add("zl"); List<String> toList = names.stream().toList(); }
|
1 2 3
| default List<T> toList() { return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray()))); }
|
- List.copyOf()
返回一个不可变的集合副本,并且不能接受集合中的空值1 2 3 4 5 6 7
| @Test @SneakyThrows public void testCopy(){ List<String> names = Arrays.asList("zs", "ls", "ww"); List<String> names_bak = List.copyOf(names); }
|
2.HTTPclient
有时候我们需要做一个小项目,为了尽量减小项目的体量和避免外部依赖的侵入性我们可以用过内置的api进行接口调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void testHttpClient() throws Exception { HttpClient client = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(3)) .followRedirects(HttpClient.Redirect.ALWAYS) .build(); HttpRequest request = HttpRequest.newBuilder() .GET().uri(URI.create("http://www.baidu.com")) .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { String body = response.body(); log.info("response: {}", body); } else { log.warn("request error, status code {}", response.statusCode()); } }
|
3.null in java
java的null变量是可以隐藏在任何类型背后的,而NullPointException是我们最讨厌的报错,所以我们需要在程序中花费大量的时间去进行null的判断,当方法返回null的时候我们都需要花费大量的精力去判断这是有意的缺失还是故障状态,所以我们应该善用jdk帮我们提供的api。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void testOptional() { String obj = null; Optional<String> aaa = Optional.of("aaa"); Optional<String> bbb = Optional.ofNullable(obj); if (aaa.isPresent()) { log.info("aaa not null, value is {}", aaa.get()); } String result = Optional.ofNullable(obj).orElse("bbb"); log.info("default value is {}", result); result = bbb.orElseThrow(IllegalArgumentException::new); }
|
4.String类新方法
Java11之前我们想要对String进行一些判空操作的时候往往会引入Commons-lang3包,因为自带的String方法实在太少了,而Java11之后String有新增一些比较实用的方法
- isBlank():如果字符串为空或仅包含空格代码点,则此方法返回true。
- lines():此方法返回从字符串中提取的行流,并用\ n,\ r等行终止符分隔。
- strip(),stripLeading(),stripTrailing() :这些方法用于从字符串中去除空格。 顾名思义, strip()将删除前导和尾随空格。 但是, stripLeading()将仅删除前导空格,而stripTrailing()将仅删除尾随空格
- repeat(int n) :此方法返回一个新字符串,该字符串的值是该字符串的重复n次的串联
1 2 3 4 5 6 7 8 9 10
| @Test public void testStr() { var blank = " "; assert blank.isBlank(); var str = " hello world "; assert Objects.equals(str.strip(), "hello world"); assert Objects.equals(str.stripLeading(), "hello world "); assert Objects.equals(str.stripTrailing(), " hello world"); assert Objects.equals(str.repeat(2), " hello world hello world "); }
|
4.java基于值类型 (Value Types)
在Java11中明确定义了基于值的类型,值类型是一种数据类型,旨在按值传入和传出方法,并按值存储在数据结构中。
基于值的类是Container类,是基于值的类型的包装器,其中基于值的类的实例遵循以下原则(来自Java文档):
- 该类是final的(尽管可能包含对可变对象的引用),并且只定义final字段,并且不存在继承或者实现
- 具有equals,hashCode和toString的实现,这些实现仅根据实例的状态而不是根据其标识或任何其他对象或变量的状态进行计算
- 没有可访问的构造函数(或者明确该构造以后会删除,所以String不满足该条件),而是通过工厂方法实例化的,这些方法不承诺返回实例的身份
- 不使用身份敏感的操作,例如实例之间的引用相等(==),而是基于equals被视为相等,因为上边不保证生成相同或者不同的实例
- 在相等时可以自由替换,这意味着在任何计算或方法调用中互换等于equals()的任意两个实例x和y都不会在行为上产生任何可见的变化。
- 通过工厂方法获取的实例不保证每次都是不同的实例(integer就存在缓存-128-127之间只生成一份)
显而易见Java语言直接支持的唯一值类型是八种原始类型和Optional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Deprecated(since="9", forRemoval = true) public Integer(int value) { this.value = value; }
public static Integer valueOf(String s) throws NumberFormatException { return Integer.valueOf(parseInt(s, 10)); }
@IntrinsicCandidate public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
|
5.AutoCloseable
我们都知道Java的Object对象有一个finalize方法,所以我们所有的对象都会存在该方法并且我们可以重写它(继承带来的弊端)。该方法会对象不存在引用的时候进行垃圾回收时执行一次,通常我们会实现该方法在该方法中释放IO或者链接或者资源,但是它不是一个线程安全的操作,而且我们永远也不知道它什么时候会被调用(假设在没有引用之前它先晋升到了老年代,那么资源就挂在了老年代,很恐怖的事情),它也会给垃圾回收器带来负担,因为处理它会增加时间,也不能保证调用它的时候会不会出现线程安全问题。比如我们现在有一个对象它有一个ArrayList字段,我们想要在对象垃圾回收的时候释放list,我们都知道释放list需要调用list的clear方法,其实我们都知道ArrayList不是一个线程安全的集合,如果真的这样做很可能会出现并发修改的异常,而且因为是重写了finalize方法所以我们不可能对方法加锁,所以jdk官方也认识到了这一点在jdk9版本将该方法设置为过时的方法了,我们可以通过实现AutoCloseable接口通过try with语法去操作资源并保证资源释放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Data @Slf4j public class DataSourceConnection implements AutoCloseable{
private String url; private String connection;
public DataSourceConnection(String url) { this.url = url; this.connection = url + "conn"; }
@Override public void close() throws Exception { log.info("关闭链接,释放资源====>"); } }
|
1 2 3 4 5 6 7
| @Test public void testClose() throws Exception { try (DataSourceConnection connection = new DataSourceConnection("rul")) { String conn = connection.getConnection(); } }
|
6.break label
其实这个也不算是api了,它只能算是一个大家都没注意的语法特性,Java没有像c中的goto语句,想要实现任意的循环跳转就要使用label
我们都知道break和continue分别是结束当且循环和结束这一轮循环,如果是多层for循环嵌套的话就不能直接退出到指定的循环层级中,所以我们这里借助lable实现该功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (j == 3) { break; } System.out.print("" + i + j + " "); } System.out.println(); } System.out.println("This is end");
|
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
| for (int i = 0; i < 5; i++) { Label_inner: for (int j = 0; j < 5; j++) { if (j == 3) { continue Label_inner; } System.out.print("" + i + j + " "); } System.out.println(); } System.out.println("This is end");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Label_outer: for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { if (j == 3) { break Label_outer; } System.out.print("" + i + j + " "); } System.out.println(); } System.out.println("This is end");
|
7.Predicate断言型函数接口
Predicate我们会经常使用,因为Java8只从有了stream流之后我们经常使用filter方法进行集合的过滤筛选,有很多内置api帮我们提供了方法引用符合我们使用场景的时候只需引用就行,但是因为是方法引用所以它不支持非(操作)或者组合操作,这个时候就可以使用Predicate内置的方法帮我们进行增强了,如下
1 2 3 4 5 6 7
| @Test public void testPredicate() { List<List<?>> list1 = List.of(List.of("zz"), Collections.emptyList()); List<List<?>> list2 = list1.stream().filter(Predicate.not(List::isEmpty)).toList(); System.out.println(list2); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void testPredicate() { List<String> names = List.of("zs", "ls", "ww", "lxy", "ywj", "suaf"); List<String> names2 = names.stream().filter(s -> { if (!s.isBlank() && s.length() <= 3 && !s.startsWith("w")) { return true; } else { return false; } }).toList(); Predicate<String> isNotStartsWith = s -> !s.startsWith("w"); Predicate<String> shorterThan4 = s -> s.length() <= 3; List<String> names3 = names.stream().filter(Predicate.not(String::isBlank).and(isNotStartsWith).and(shorterThan4)).toList(); assert names3.equals(names2); }
|
8.Comparator比较器
Comparator比较器我们会经常使用,因为Java8自从有了stream流之后我们经常使用sort方法进行集合的排序,有很多内置api帮我们提供了默认的比较方法,在符合我们使用场景的时候只需使用方法引用就行,但是因为是方法引用所以它不支持倒序或者多值比较什么的,如下:
1 2 3 4 5 6 7 8
| @Test public void testComparable() { List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi"); names.sort(null); names.forEach(System.out::println); }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testComparator() { List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi"); Comparator<String> comparator = Comparator.comparingInt(String::length); names.sort(comparator); names.forEach(System.out::println); }
|
1 2 3 4 5 6 7 8 9 10 11
| @Test public void testComparator() { List<Integer> numbers = List.of(123, 21, 32, 125, 1, 321); List<Integer> list = numbers.stream().sorted(Integer::compare).toList(); System.out.println("list = " + list); Comparator<Integer> comparator = Integer::compare; List<Integer> list2 = numbers.stream().sorted(comparator.reversed()).toList(); System.out.println("list2 = " + list2); }
|
1 2 3 4 5 6 7 8
| @Test public void testComparator() { List<String> names = List.of("zs", "ls", "ww", "lxy", "ywj", "suaf"); Comparator<String> comparing = Comparator.comparing(String::length); List<String> list1 = names.stream().sorted(comparing).toList(); List<String> list2 = names.stream().sorted(comparing.reversed()).toList(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Data @AllArgsConstructor class User { private String userName; private Integer age; } @Test public void testComparator23() { ArrayList<User> users = new ArrayList<>() {{ add(new User("zs", 23)); add(new User("ls", 24)); add(new User("ww", 25)); add(new User("zl", 26)); add(new User("zqq", 26)); add(null); }}; Comparator<User> comparatorByAge = Comparator.comparing(User::getAge); Comparator<User> comparatorByName = Comparator.comparing(User::getUserName); List<User> list1 = users.stream().sorted(Comparator.nullsLast(comparatorByAge.thenComparing(comparatorByName))).toList(); List<User> list2 = users.stream().sorted(Comparator.nullsFirst(comparatorByAge.thenComparing(comparatorByName).reversed())).toList(); System.out.println("list1 = " + list1); System.out.println("list2 = " + list2); }
|
9.Java shebang
我们一直羡慕python作为脚本语言的时候能直接执行,而一个Java代码你需要先使用Javac编译成class文件,然后再使用Java命令运行,这是一个简单Java脚本最繁琐的地方,好在Java推出了shebang行
1 2 3 4 5 6
| # !/path/you java path --source 17 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } }
|
10.string相关
字符串jdk也一直在优化,曾经不同版本的字符串可能会有点性能差异,但是现在经过优化之后好了很多但是我们还是应该注意使用的时候按照规范使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Test public void testStringJoin() throws Exception { List<String> string = List.of("a", "b", "c"); String join = ""; for (String s : string) { join += s; } System.out.println("join = " + join); StringBuilder sb = new StringBuilder(); for (String s : string) { sb.append(s); } System.out.println("sb.toString() = " + sb); }
|
1 2 3 4 5 6 7 8
| @Test public void testNumber2Str() throws Exception { int num = 1; Integer num2 = 2; String num_str = 1 + ""; String num_str2 = num2.toString(); String num_str1 = Integer.toString(num); }
|