LOGI - Java
type: channel
link: https://www.logi.im/tag/Java/
items: The Four Arithmetic Operation of BigInteger
items: Resolving Spring Boot Configuration Annotation Processor Not Configured Warning in IntelliJ IDEA
items: Field, Attribute, and Property in Java
items: Double Curly Braces Initialization in Java
items: Java Concurrency Basics
items: 无颜色目录树
items: Annotations
items: Aggregate Operations
items: Lambda Expressions
items: Concurrency

The Four Arithmetic Operation of BigInteger
type: item
date: 2022-01-04T08:32:00+00:00
description: 大整数的四则运算，很多数人都写过，本文提供一个 Java 版本的朴素实现，即模拟竖式。除法使用了递归，效率不高，递推公式如下：求商 = 连接( 被除数大于等于除数的最小前缀 / 除数, 逐位连接(上式余数, 被除数剩余部分)[期间, 若连接后的被除数小于除数, 商上零], [连接完毕后, 若被除数不小于除数, 求商(连接后的被除数, 除数)] )当商高于一千位时，递归版本栈溢出，改为等价迭代后，一亿位被除数测试通过。 Java Implementation package im.logi.math; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.function.BiFunction; import java.util.stream.IntStream; /** * @author logi * @version 1.0 * @time 2022/1/5 16:08 */ public class BigInteger implements Comparable<BigInteger>, Cloneable { private static final BigInteger ZERO = new BigInteger("0"); private static final BigInteger ONE = new BigInteger("1"); private boolean positive = true; private StringBuilder value; private BigInteger() { value = new StringBuilder(); } public BigInteger(String valueString) { int beginIndex = 0; if (valueString.charAt(0) == '-') { beginIndex = 1; positive = false; } else if (valueString.charAt(0) == '+') beginIndex = 1; while (beginIndex < valueString.length() && valueString.charAt(beginIndex) == '0') beginIndex++; // 仅是一个符号或全部为零，回退 if (beginIndex == valueString.length()) beginIndex--; value = new StringBuilder(valueString.length() - beginIndex); for (int i = beginIndex; i < valueString.length(); i++) { char c = valueString.charAt(i); if (c < '0' || c > '9') throw new IllegalArgumentException(); value.append(c); } setZeroPositive(); } // 只存正零 private void setZeroPositive() { if (value.length() == 1 && value.charAt(0) == '0') positive = true; } @Override protected Object clone() throws CloneNotSupportedException { BigInteger clone = (BigInteger) super.clone(); clone.positive = positive; clone.value = new StringBuilder(value); return clone; } @Override public boolean equals(Object obj) { if (obj instanceof BigInteger o) return positive == o.positive && value.toString().equals(o.value.toString()); return false; } @Override public int compareTo(BigInteger o) { if (positive != o.positive) return positive ? 1 : -1; int absRet = value.length() - o.valu…

Resolving Spring Boot Configuration Annotation Processor Not Configured Warning in IntelliJ IDEA
type: item
date: 2021-10-03T11:08:00+00:00
description: 在 IDEA 2021.2.2 中编写 Spring Boot 项目，打开使用了 @ConfigurationProperties 注解的类时，标签页下方会出现 Spring Boot Configuration Annotation Processor not configured 的提示，而提示给出的文档链接已经 404 了。搜索后发现 Spring Boot Configuration Annotation Processor 会扫描被 @ConfigurationProperties 注解的类，以此生成配置元数据，这些元数据可以被编译器读取用于 application.properties 中配置项的自动补全和错误检查。根据 Spring Boot 文档，只要引入相应依赖并重新编译项目便可生成配置元数据。但即便如此，IDEA 的提示有时并不消失，此时需要重载项目。之后，提示文字转为 Re-run Spring Boot Configuration Annotation Processor to update generated metadata，并且背景由红色转为深灰。这个提示只是在说，如果更改了类，记得重新编译更新元数据，并非警告，无需理会。此时打开 application.properties 就会发现自动补全已经可以正常使用了。网络上的一些文章说的打开 IDEA 设置里的 Enable annotation processing 实际是另一个功能，与此无关。[...]

Field, Attribute, and Property in Java
type: item
date: 2021-09-13T12:59:00+00:00
description: FieldA data member of a class. Unless specified otherwise, a field is not static.类的数据成员。除非指定，它不是静态的。举例：public class Customer { // Fields of Customer final String field1 = "Fixed Value"; int name; }AttributeAn attribute is another term for a field. It’s typically a public field that can be accessed directly.Field 的别称，它通常是可以直接访问的 public field，例如数组的长度。（Java SE 术语表中无此定义）PropertyCharacteristics of an object that users can set, such as the color of a window.对象的特征，用户可以设置它，例如窗户的颜色。举例：public class Window { // Property of Window private String color; public String getColor() { return this.color; } public void setColor(String color) { this.color = color; } }ReferencesWhat is the difference between field, variable, attribute, and property in JavaWhat is the difference between field, variable, attribute, and property in Java POJOs?Glossary of Terms

Double Curly Braces Initialization in Java
type: item
date: 2021-08-26T09:19:00+00:00
description: 准备给之前 Python 写的 QQ 机器人加点功能，发现升级后的依赖库变动很大，加上之前有些 Bug，瞬间不想用了，用上游框架重写吧。上游项目基于 Kotlin，我不熟悉，但提供 Java API，克隆示例代码，OK，可以运行。正准备往前推进，突然发现 有段代码 的语法我竟然看不懂，心想 Java 用了挺长时间不至于吧。[...]

Java Concurrency Basics
type: item
date: 2021-06-24T13:44:00+00:00
description: Java Concurrency1. IntroductionJava Concurrency 是一个涵盖 Java 平台多线程，并发和并行的术语，包括并发工具，并发问题和并发解决方案。本文将介绍多线程的核心概念，并发结构，并发问题，以及多线程的代价和优点。What is Multithreading?多线程即同一应用内部执行多个线程。假如单线程代表只有一个 CPU 执行你的应用，那么多线程应用中，则同时存在多个 CPU 执行不同部分的代码。然而，单线程并不等同于单个 CPU。通常，一个 CPU 把执行时间分享给多个线程，每隔一段时间，CPU 会切换一个线程。当然，让不同线程被不同 CPU 执行也是可能的。Why Multithreading?在应用中使用多线程有许多原因，最常见的是以下几个：更好地利用单个 CPU更好地利用多个 CPU 或多核更快的用户响应更公平的用户响应Better Utilization of a Single CPU最常见的原因是可以更好利用计算机中的资源。例如，如果一个线程正在等待网络请求响应，另一个线程可以同时使用 CPU 做其它事情。此外，如果计算机有多个 CPU，或者 CPU 拥有多个运算核心，那么多线程也可以帮助应用利用这些额外的核心。Better Utilization of Multiple CPUs or CPU Cores如果一台计算机包含多个 CPU 或 CPU 含有多个执行核心，那么你需要通过多线程让你的应用利用所有 CPU 或 CPU 核心。单线程最多可以利用单个 CPU，并且就像我上面提到的，有时还不能完全利用它。Better User Experience with Regards to Responsiveness使用多线程的另一个原因是提供更好的用户体验。例如，你点击了界面上的一个按钮，它将触发一个网络请求，那么请求由哪个线程发出是很重要的。如果你仍然使用更新 GUI 的线程，那么在等待请求响应时，用户可能无法操作界面。相反，这一请求可以被后台线程执行，那么界面线程就可以同时响应其它用户操作。Better User Experience with Regards to Fairness第四个原因是在各个用户间更公平地共享计算机资源。就像例子想象的那样，一个接收客户端请求的服务器，如果仅有一个线程执行这些请求，当某个客户端发送了一个长耗时请求时，其它客户端将不得不等待那个请求结束。如果每个客户端请求被它们自己的线程执行，就没有任何一个任务可以完全独占CPU。Multithreading vs. Multitasking以前，那些只有一个 CPU 的计算机只能同时运行一个程序。大多数小型机没有足够的性能同时执行多个程序，所以它们没有那样做。公平的说，大型系统具备同时执行多个程序的能力要比个人电脑早许多年。Multitasking随后出现了多任务，即计算机可以同时执行多个程序（任务或进程），但这并非真正的同时，而是单个 CPU 被多个程序共享，操作系统会切换不同的程序执行，每个程序运行一小段时间。多任务也为开发者带来了新挑战。程序再也不能假定拥有所有 CPU 时间，同样还有内存或其它计算资源。程序中的 “良好公民” 应该释放所有不再使用的资源，这样其它程序才能获得它们。Multithreading最后出现的是多线程，它意味着你可以在同一应用内部执行多个线程。单线程执行可以想象成只有一个 CPU 执行这个程序。当你拥有多线程时，就像同一程序同时被不同 CPU 执行。Multithreading is Hard多线程是增强某类程序性能的绝佳手段。然而，实现多线程比多任务更具挑战性。同一程序中的多个线程会同时读写相同的内存单元。这会导致单线程应用中不会出现的错误。某些错误可能不会出现在单 CPU 机器，因为这种情况下，两个线程永远不能真正同时运行。然而，现代计算机的 CPU 都拥有多核心，有些计算机还拥有多个 CPU，这意味着不同线程可以被不同核心或 CPU 同时执行。如果一个线程正在读取另一个线程将要写入的内存地址，那么它最终读到的将是哪个值？旧的值？第二个线程写入后的值？还是一个介于两者之间的值？又或者，两个线程同时向同一内存地址写入数据，当它们完成时，该内存位置的值哪个呢？第一个线程写入的？第二个线程写入的？还是两个值的混合呢？如果没有恰当的处理，以上结果都有可能出现。它们的行为甚至是不可预测的，结果每次都可能不同。因此了解和采取恰当措施对开发者来说是十分重要的——即学习控制线程如何访问共享资源，如内存，文件，数据库等。这就是本文要讨论的话题之一。Multithreading and Concurrency in JavaJava 是第一批让开发者能方便地使用多线程的语言之一，…

无颜色目录树
type: item
date: 2021-01-28T03:55:00+00:00
description: Linux Version➜ LOGI tree /etc/apt /etc/apt ├── apt.conf.d │ ├── 01-vendor-ubuntu │ ├── 01autoremove │ ├── 01autoremove-kernels │ ├── 10periodic │ ├── 15update-stamp │ ├── 20archive │ ├── 20auto-upgrades │ ├── 20packagekit │ ├── 20snapd.conf │ ├── 50command-not-found │ ├── 50unattended-upgrades │ ├── 70debconf │ └── 99update-notifier ├── auth.conf.d ├── preferences.d ├── sources.list.bak ├── sources.list.d │ ├── 163.list │ ├── 163.list.save │ └── deadsnakes-ubuntu-ppa-focal.list └── trusted.gpg.d ├── deadsnakes_ubuntu_ppa.gpg ├── ubuntu-keyring-2012-archive.gpg ├── ubuntu-keyring-2012-cdimage.gpg └── ubuntu-keyring-2018-archive.gpg 5 directories, 21 filesSelf Implementation➜ LOGI java DirectoryTree //wsl$/Ubuntu/etc/apt \\WSL$\UBUNTU\ETC\APT ├── apt.conf.d │ ├── 01-vendor-ubuntu │ ├── 01autoremove │ ├── 01autoremove-kernels │ ├── 10periodic │ ├── 15update-stamp │ ├── 20archive │ ├── 20auto-upgrades │ ├── 20packagekit │ ├── 20snapd.conf │ ├── 50command-not-found │ ├── 50unattended-upgrades │ ├── 70debconf │ └── 99update-notifier ├── auth.conf.d ├── preferences.d ├── sources.list.bak ├── sources.list.d │ ├── 163.list │ ├── 163.list.save │ └── deadsnakes-ubuntu-ppa-focal.list └── trusted.gpg.d ├── deadsnakes_ubuntu_ppa.gpg ├── ubuntu-keyring-2012-archive.gpg ├── ubuntu-keyring-2012-cdimage.gpg └── ubuntu-keyring-2018-archive.gpg 5 directories, 21 filesSource CodeRustuse std::{path, fs, io, env}; struct DirectoryTree<'a> { file_count: u32, directory_count: u32, root: &'a str, } impl<'a> DirectoryTree<'a> { fn print(&mut self) { if path::Path::new(self.root).exists() { println!("{}", self.root.to_uppercase()); self.print_sub_tree(self.root, "").err(); print!("\n{} director{}, {} file{}", self.directory_count, if self.directory_count > 1 { "ies" } else { "y" }, self.file_count, if self.file_count > 1 { "s" } else { " " }, ) } } fn print_sub_tree(&mut self, folder: &str, prefix: &str) -> io::Result<()> { let children: Vec<_> = fs::read_dir(folder)? .map(|res| res.unwrap().p…

Annotations
type: item
date: 2021-01-21T02:36:00+00:00
description: Annotation 是一种元数据，它为程序提供不属于自身的信息，对被注解代码的操作不起直接作用。注解有很多用处，包括：提供给编译器的信息 —— 编译器可以根据注解检测错误或抑制警告编译期和部署期处理 —— 工具可以根据注解生成代码、XML 等文件运行时处理 —— 有些注解可以在运行时被检测到下文介绍注解可以被用到什么地方，如何使用，JavaSE 提供了哪些预定义注解，怎样在可插拔类型系统中使用类型注解实现强大的类型检查，怎样实现重复注解。[...]

Aggregate Operations
type: item
date: 2021-01-17T15:50:00+00:00
description: 备注 为了更好理解本章概念，请复习 Lambda Expressions 和 Method References。 你为何使用容器？不是简单的为了存储对象吧。大多数情况下，我们使用容器检索存储在其中的元素。回想 Lambda Expressions 描述的场景。假定你正在编写社交网络应用。你想创建一个可以让管理员执行任何操作的方法，例如，发送消息给满足特定条件的成员。和之前一样，假定成员使用如下 Person 类表示：public class Person { public enum Sex { MALE, FEMALE } String name; LocalDate birthday; Sex gender; String emailAddress; // ... public int getAge() { // ... } public String getName() { // ... } }如下代码使用 for-each 循环打印了 roster 容器中所有成员的姓名：for (Person p: roster) { System.out.println(p.getName()); }如下代码使用聚集操作 forEach 完成相同动作：roster .stream() .forEach(e -> System.out.println(e.getName));尽管本例中，聚集操作版本比普通循环长，但之后你会发现，处理复杂任务的大量数据，聚集更简洁。本篇内容简介：管道和流聚集操作与迭代器的区别涉及的完整代码见 BulkDataOperationsExamples。[...]

Lambda Expressions
type: item
date: 2021-01-11T08:45:00+00:00
description: 匿名类的一大问题是，如果实现很简单，例如单方法接口，那么它的语法显得笨拙且模糊。这种情况下，你通常试图将函数作为参数传递给其它方法，比如用户点击按钮要采取的动作。Lambda [ˈlæmdə] 表达式允许你把函数当成方法参数，或把代码看成数据。前章 Anonymous Classes 展示了如何不具名实现基类。尽管它比具名类简洁，但对于单方法类，也有点多余和累赘。Lambda 表达式允许你更紧凑地表达单方法类型实例。本章涵盖如下话题：Lambda Expressions 的理想用例方式 1: 创建搜索匹配单特征成员的方法方式 2: 创建更通用的搜索方法方式 3: 在局部类中指定搜索条件代码方式 4: 在匿名类中指定搜索条件代码方式 5: 在 Lambda Expression 中指定搜索条件代码方式 6: 使用标准函数接口的 Lambda Expressions方式 7: 让 Lambda Expressions 贯穿你的应用方式 8: 更具扩展性地使用泛型方式 9: 使用以 Lambda Expression 为参数的 Aggregate OperationsGUI 应用中的 Lambda ExpressionsLambda Expressions 语法访问封闭域内的局部变量目标类型目标类型和方法参数序列化[...]

Concurrency
type: item
date: 2021-01-09T18:01:00+00:00
description: 电脑用户理所当然地认为系统可以同时处理多个任务。他们假定可以一边处理 Word，一边下载文件，一边管理打印队列，还能进行音乐串流。甚至单个应用也被期待同时完成多个任务。例如，那个音频串流程序必须同时从网络读取数字音频，解压，管理播放，还要更新显示。甚至 Word 处理程序也总是时刻准备好响应键盘和鼠标事件，无论它多么忙于格式化文本或者更新显示信息。能够同时完成这些事情的软件称为 concurrent 软件。Java 平台从地基设计支持并发编程，语言和类库都支持基本的并发操作。从 5.0 版本开始，Java 平台也包含了高级并发 API。本课程将介绍平台的基本并发支持，并总结一些 java.util.concurrent 包下的高级 API。[...]