原文:Java Coding Problems
协议:CC BY-NC-SA 4.0
贡献者:飞龙
本文来自【ApacheCN Java 译文集】 ,自豪地采用谷歌翻译 。
本章包括 21 个涉及 JEP286 或 Java 局部变量类型推断 (LVTI )的问题,也称为var
类型。这些问题经过精心设计,以揭示最佳实践和使用var
时所涉及的常见错误。到本章结束时,您将了解到将var
推向生产所需的所有知识。
问题
使用以下问题来测试您的类型推断编程能力。我强烈建议您在使用解决方案和下载示例程序之前,先尝试一下每个问题:
简单var
示例 :编写一个程序,举例说明类型推断(var
)在代码可读性方面的正确用法。
将var
与原始类型结合使用 :编写一个程序,举例说明将var
与 Java 原始类型(int
、long
、float
、double
结合使用。
使用var
和隐式类型转换来维持代码的可维护性 :编写一个程序,举例说明var
和隐式类型转换 如何维持代码的可维护性。
显式向下转换或更好地避免var
:编写一个程序,举例说明var
和显式向下转换的组合,并解释为什么要避免var
。
如果被调用的名称没有包含足够的人性化类型信息,请避免使用var
:请举例说明应避免使用var
,因为它与被调用的名称 的组合会导致人性化信息的丢失。
结合 LVTI 和面向接口编程技术 :编写一个程序,通过面向接口编程 技术来举例说明var
的用法。
结合 LVTI 和菱形运算符 :编写一个程序,举例说明var
和菱形运算符 的用法。
使用var
分配数组 :编写一个将数组分配给var
的程序。
在复合声明中使用 LVTI :解释并举例说明 LVTI 在复合声明中的用法。
LVTI 和变量范围 :解释并举例说明为什么 LVTI 应该尽可能地缩小变量的范围。
LVTI 和三元运算符 :编写几个代码片段,举例说明 LVTI 和三元运算符 组合的优点。
LVTI 和for
循环 :写几个例子来举例说明 LVTI 在for
循环中的用法。
LVTI 和流 :编写几个代码片段,举例说明 LVTI 和 Java 流的用法。
使用 LVTI 分解嵌套的/大的表达式链 :编写一个程序,举例说明如何使用 LVTI 分解嵌套的/大的表达式链。
LVTI 和方法返回和参数类型 :编写几个代码片段,举例说明 LVTI 和 Java 方法在返回和参数类型方面的用法。
LVTI 和匿名类 :编写几个代码片段,举例说明 LVTI 在匿名类中的用法。
LVTI 可以是final
和有效的final
:写几个代码片段,举例说明 LVTI 如何用于final
和有效的final
变量。
LVTI 和 Lambda :通过几个代码片段解释如何将 LVTI 与 Lambda 表达式结合使用。
LVTI 和null
初始化器、实例变量和catch
块变量 :举例说明如何将 LVTI 与null
初始化器 、实例变量和catch
块结合使用。
LVTI 和泛型类型T
:编写几个代码片段,举例说明如何将 LVTI 与泛型类型结合使用。
LVTI、通配符、协变和逆变 :编写几个代码片段,举例说明如何将 LVTI 与通配符、协变和逆变结合使用。
解决方案
以下各节介绍上述问题的解决方案。记住,通常没有一个正确的方法来解决一个特定的问题。另外,请记住,这里显示的解释仅包括解决问题所需的最有趣和最重要的细节。您可以下载示例解决方案以查看更多详细信息并尝试程序 。
78 简单var
示例
从版本 10 开始,Java 附带了 JEP286 或 JavaLVTI,也称为var
类型。
var
标识符不是 Java 关键字 ,而是保留类型名 。
这是一个 100% 编译特性,在字节码、运行时或性能方面没有任何副作用。简而言之,LVTI 应用于局部变量,其工作方式如下:编译器检查右侧并推断出实类型(如果右侧是一个初始化器 ,则使用该类型)。
此功能可确保编译时安全。这意味着我们不能编译一个试图实现错误赋值的应用。如果编译器已经推断出var
的具体/实际类型,我们只能赋值该类型的值。
LVTI 有很多好处;例如,它减少了代码的冗长,减少了冗余和样板 代码。此外,LVTI 可以减少编写代码所花的时间,特别是在涉及大量声明的情况下,如下所示:
// without var
Map> evenAndOddMap...
// with var
var evenAndOddMap = ...
一个有争议的优点是代码可读性。一些声音支持使用var
会降低代码可读性,而另一些声音则支持相反的观点。根据用例的不同,它可能需要在可读性上进行权衡,但事实是,通常情况下,我们非常关注字段(实例变量)的有意义的名称,而忽略了局部变量的名称。例如,让我们考虑以下方法:
public Object fetchTransferableData(String data)
throws UnsupportedFlavorException, IOException {
StringSelection ss = new StringSelection(data);
DataFlavor[] df = ss.getTransferDataFlavors();
Object obj = ss.getTransferData(df[0]);
return obj;
}
这是一个简短的方法;它有一个有意义的名称和一个干净的实现。但是检查局部变量的名称。它们的名称大大减少(它们只是快捷方式),但这不是问题,因为左侧提供了足够的信息,我们可以很容易地理解每个局部变量的类型。现在,让我们使用 LVTI 编写以下代码:
public Object fetchTransferableData(String data)
throws UnsupportedFlavorException, IOException {
var ss = new StringSelection(data);
var df = ss.getTransferDataFlavors();
var obj = ss.getTransferData(df[0]);
return obj;
}
显然,代码的可读性降低了,因为现在很难推断出局部变量的类型。如下面的屏幕截图所示,编译器在推断正确的类型方面没有问题,但是对于人类来说,这要困难得多:
这个问题的解决方案是在依赖 LVTI 时为局部变量提供一个有意义的名称。例如,如果提供了局部变量的名称,代码可以恢复可读性,如下所示:
public Object fetchTransferableData(String data)
throws UnsupportedFlavorException, IOException {
var stringSelection = new StringSelection(data);
var dataFlavorsArray = stringSelection.getTransferDataFlavors();
var obj = stringSelection.getTransferData(dataFlavorsArray[0]);
return obj;
}
然而,可读性问题也是由这样一个事实引起的:通常,我们倾向于将类型视为主要信息,将变量名视为次要信息,而这应该是相反的。
让我们再看两个例子来执行上述语句。使用集合(例如,List
)的方法如下:
// Avoid
public List fetchPlayersByTournament(String tournament) {
var t = tournamentRepository.findByName(tournament);
var p = t.getPlayers();
return p;
}
// Prefer
public List fetchPlayersByTournament(String tournament) {
var tournamentName = tournamentRepository.findByName(tournament);
var playerList = tournamentName.getPlayers();
return playerList;
}
为局部变量提供有意义的名称并不意味着陷入过度命名 技术。
例如,通过简单地重复类型名来避免命名变量:
// Avoid
var fileCacheImageOutputStream
= new FileCacheImageOutputStream(..., ...);
// Prefer
var outputStream = new FileCacheImageOutputStream(..., ...);
// Or
var outputStreamOfFoo = new FileCacheImageOutputStream(..., ...);
79 对原始类型使用var
将 LVTI 与原始类型(int
、long
、float
和double
)一起使用的问题是,预期类型和推断类型可能不同。显然,这会导致代码中的混乱和意外行为。
这种情况下的犯罪方是var
类型使用的隐式类型转换 。
例如,让我们考虑以下两个依赖显式原始类型的声明:
boolean valid = true; // this is of type boolean
char c = 'c'; // this is of type char
现在,让我们用 LVTI 替换显式原始类型:
var valid = true; // inferred as boolean
var c = 'c'; // inferred as char
很好!到目前为止没有问题!现在,让我们看看另一组基于显式原始类型的声明:
int intNumber = 10; // this is of type int
long longNumber = 10; // this is of type long
float floatNumber = 10; // this is of type float, 10.0
double doubleNumber = 10; // this is of type double, 10.0
让我们按照第一个示例中的逻辑,用 LVTI 替换显式原始类型:
// Avoid
var intNumber = 10; // inferred as int
var longNumber = 10; // inferred as int
var floatNumber = 10; // inferred as int
var doubleNumber = 10; // inferred as int
根据以下屏幕截图,所有四个变量都被推断为整数:
这个问题的解决方案包括使用显式 Java 字面值 :
// Prefer
var intNumber = 10; // inferred as int
var longNumber = 10L; // inferred as long
var floatNumber = 10F; // inferred as float, 10.0
var doubleNumber = 10D; // inferred as double, 10.0
最后,让我们考虑一个带小数的数字的情况,如下所示:
var floatNumber = 10.5; // inferred as double
变量名表明10.5
是float
,但实际上是推断为double
。因此,即使是带小数的数字(尤其是带小数的数字),也建议使用字面值 :
var floatNumber = 10.5F; // inferred as float
80 使用var
和隐式类型转换来维持代码的可维护性
在上一节中,“将var
与原始类型结合使用”,我们看到将var
与隐式类型转换 结合使用会产生实际问题。但在某些情况下,这种组合可能是有利的,并维持代码的可维护性。
让我们考虑以下场景,我们需要编写一个方法,该方法位于名为ShoppingAddicted
的外部 API 的两个现有方法之间(通过推断,这些方法可以是两个 Web 服务、端点等)。有一种方法专门用于返回给定购物车的最佳价格。基本上,这种方法需要一堆产品,并查询不同的在线商店,以获取最佳价格。
结果价格返回为int
。此方法的存根如下所示:
public static int fetchBestPrice(String[] products) {
float realprice = 399.99F; // code to query the prices in stores
int price = (int) realprice;
return price;
}
另一种方法将价格作为int
接收并执行支付。如果支付成功,则返回true
:
public static boolean debitCard(int amount) {
return true;
}
现在,通过对该代码进行编程,我们的方法将充当客户端,如下所示(客户可以决定购买哪些商品,我们的代码将为他们返回最佳价格并相应地借记卡):
// Avoid
public static boolean purchaseCart(long customerId) {
int price = ShoppingAddicted.fetchBestPrice(new String[0]);
boolean paid = ShoppingAddicted.debitCard(price);
return paid;
}
但是过了一段时间,ShoppingAddicted
API 的拥有者意识到他们通过将实际价格转换成int
来赔钱(例如,实际价格是 399.99,但在int
形式中,它是 399.0,这意味着损失 99 美分)。因此,他们决定放弃这种做法,将实际价格返回为float
:
public static float fetchBestPrice(String[] products) {
float realprice = 399.99F; // code to query the prices in stores
return realprice;
}
因为返回的价格是float
,所以debitCard()
也会更新:
public static boolean debitCard(float amount) {
return true;
}
但是,一旦我们升级到新版本的ShoppingAddicted
API,代码将失败,并有可能从float
到int
异常的有损转换 。这是正常的,因为我们的代码需要int
。由于我们的代码不能很好地容忍这些修改,因此需要相应地修改代码。
然而,如果我们已经预见到这种情况,并且使用了var
而不是int
,那么由于隐式类型转换 ,代码将不会出现问题:
// Prefer
public static boolean purchaseCart(long customerId) {
var price = ShoppingAddicted.fetchBestPrice(new String[0]);
var paid = ShoppingAddicted.debitCard(price);
return paid;
}
81 显式向下转换或更好地避免var
在“将var
与原始类型结合使用”一节中,我们讨论了将字面值 与原始类型结合使用(int
、long
、float
和double
来避免隐式类型转换 带来的问题。但并非所有 Java 原始类型都可以利用字面值 。在这种情况下,最好的方法是避免使用var
。但让我们看看为什么!
检查以下关于byte
和short
变量的声明:
byte byteNumber = 25; // this is of type byte
short shortNumber = 1463; // this is of type short
如果我们用var
替换显式类型,那么推断的类型将是int
:
var byteNumber = 25; // inferred as int
var shortNumber = 1463; // inferred as int
不幸的是,这两种基本类型没有可用的字面值 。帮助编译器推断正确类型的唯一方法是依赖显式向下转换:
var byteNumber = (byte) 25; // inferred as byte
var shortNumber = (short) 1463; // inferred as short
虽然这段代码编译成功并按预期工作,但我们不能说使用var
比使用显式类型带来了任何价值。因此,在这种情况下,最好避免var
和显式的向下转型。
82 如果被调用的名称没有包含足够的类型信息,请避免使用var
好吧,var
不是一颗银弹,这个问题将再次凸显这一点。以下代码片段可以使用显式类型或var
编写,而不会丢失信息:
// using explicit types
MemoryCacheImageInputStream is =
new MemoryCacheImageInputStream(...);
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = compiler.getStandardFileManager(...);
因此,将前面的代码片段迁移到var
将产生以下代码(通过从右侧目视检查被调用的名称 来选择变量名称):
// using var
var inputStream = new MemoryCacheImageInputStream(...);
var compiler = ToolProvider.getSystemJavaCompiler();
var fileManager = compiler.getStandardFileManager(...);
同样的情况也会发生在过度命名的边界上:
// using var
var inputStreamOfCachedImages = new MemoryCacheImageInputStream(...);
var javaCompiler = ToolProvider.getSystemJavaCompiler();
var standardFileManager = compiler.getStandardFileManager(...);
因此,前面的代码在选择变量的名称和可读性时不会引起任何问题。所谓的名称 包含了足够的信息,让人类对var
感到舒服。
但让我们考虑以下代码片段:
// Avoid
public File fetchBinContent() {
return new File(...);
}
// called from another place
// notice the variable name, bin
var bin = fetchBinContent();
对于人类来说,如果不检查名称 、fetchBinContent()
的返回类型,就很难推断出名称 返回的类型。根据经验,在这种情况下,解决方案应该避免var
并依赖显式类型,因为右侧没有足够的信息让我们为变量选择合适的名称并获得可读性很高的代码:
// called from another place
// now the left-hand side contains enough information
File bin = fetchBinContent();
因此,如果将var
与被调用的名称 组合使用导致清晰度损失,则最好避免使用var
。忽略此语句可能会导致混淆,并会增加理解和/或扩展代码所需的时间。
考虑另一个基于java.nio.channels.Selector
类的例子。此类公开了一个名为open()
的static
方法,该方法返回一个新打开的Selector
。但是,如果我们在一个用var
声明的变量中捕获这个返回值,我们很可能会认为这个方法可能返回一个boolean
,表示打开当前选择器的成功。使用var
而不考虑可能的清晰度损失会产生这些问题。像这样的一些问题和代码将成为一个真正的痛苦。
83 LVTI 与面向接口编程技术相结合
Java 最佳实践鼓励我们将代码绑定到抽象。换句话说,我们需要依赖于面向接口编程 的技术。
这种技术非常适合于集合声明。例如,建议声明ArrayList
如下:
List players = new ArrayList<>();
我们也应该避免这样的事情:
ArrayList players = new ArrayList<>();
通过遵循第一个示例,代码实例化了ArrayList
类(或HashSet
、HashMap
等),但声明了一个List
类型的变量(或Set
、Map
等)。由于List
、Set
、Map
以及更多的都是接口(或契约),因此很容易用List
(Set
和Map
的其他实现来替换实例化,而无需对代码进行后续修改。
不幸的是,LVTI 不能利用面向接口编程 技术。换句话说,当我们使用var
时,推断的类型是具体的实现,而不是合同。例如,将List
替换为var
将导致推断类型ArrayList
:
// inferred as ArrayList
var playerList = new ArrayList();
然而,有一些解释支持这种行为:
LVTI 在局部级别(局部变量)起作用,其中面向接口编程 技术的的使用少于方法参数/返回类型或字段类型。
由于局部变量的作用域很小,因此切换到另一个实现所引起的修改也应该很小。切换实现对检测和修复代码的影响应该很小。
LVTI 将右侧的代码视为一个用于推断实际类型的初始化器 。如果将来要修改这个初始化器 ,那么推断的类型可能不同,这将导致使用此变量的代码出现问题。
84 LVTI 和菱形运算符相结合
根据经验,如果右侧不存在推断预期类型所需的信息,则 LVTI 与菱形 运算符结合可能会导致意外的推断类型。
在 JDK7 之前,即 Coin 项目,List
将声明如下:
List players = new ArrayList();
基本上,前面的示例显式指定泛型类的实例化参数类型。从 JDK7 开始,Coin 项目引入了菱形 操作符,可以推断泛型类实例化参数类型,如下所示:
List players = new ArrayList<>();
现在,如果我们从 LVTI 的角度来考虑这个例子,我们将得到以下结果:
var playerList = new ArrayList<>();
但是现在推断出的类型是什么呢?好吧,我们有一个问题,因为推断的类型将是ArrayList,而不是ArrayList
。解释很明显:推断预期类型(String
所需的信息不存在(注意,右侧没有提到String
类型)。这指示 LVTI 推断出最广泛适用的类型,在本例中是Object
。
但是如果ArrayList不是我们的意图,那么我们需要一个解决这个问题的方法。解决方案是提供推断预期类型所需的信息,如下所示:
var playerList = new ArrayList();
现在,推断的类型是ArrayList
。也可以间接推断类型。请参见以下示例:
var playerStack = new ArrayDeque();
// inferred as ArrayList
var playerList = new ArrayList<>(playerStack);
也可以通过以下方式间接推断:
Player p1 = new Player();
Player p2 = new Player();
var listOfPlayer = List.of(p1, p2); // inferred as List
// Don't do this!
var listOfPlayer = new ArrayList<>(); // inferred as ArrayList
listOfPlayer.add(p1);
listOfPlayer.add(p2);
85 将数组赋给var
根据经验,将数组分配给var
不需要括号[]
。通过相应的显式类型定义一个int
数组可以如下所示:
int[] numbers = new int[10];
// or, less preferred
int numbers[] = new int[10];
现在,尝试直觉地使用var
代替int
可能会导致以下尝试:
var[] numberArray = new int[10];
var numberArray[] = new int[10];
不幸的是,这两种方法都无法编译。解决方案要求我们从左侧拆下支架:
// Prefer
var numberArray = new int[10]; // inferred as array of int, int[]
numberArray[0] = 3; // works
numberArray[0] = 3.2; // doesn't work
numbers[0] = "3"; // doesn't work
通常的做法是在声明时初始化数组,如下所示:
// explicit type work as expected
int[] numbers = {1, 2, 3};
但是,尝试使用var
将不起作用(不会编译):
// Does not compile
var numberArray = {1, 2, 3};
var numberArray[] = {1, 2, 3};
var[] numberArray = {1, 2, 3};
此代码无法编译,因为右侧没有自己的类型。
86 在复合声明中使用 LVTI
复合声明允许我们声明一组相同类型的变量,而无需重复该类型。类型只指定一次,变量用逗号分隔:
// using explicit type
String pending = "pending", processed = "processed",
deleted = "deleted";
将String
替换为var
将导致无法编译的代码:
// Does not compile
var pending = "pending", processed = "processed", deleted = "deleted";
此问题的解决方案是将复合声明转换为每行一个声明:
// using var, the inferred type is String
var pending = "pending";
var processed = "processed";
var deleted = "deleted";
因此,根据经验,LVTI 不能用在复合声明中。
87 LVTI 和变量范围
干净的代码最佳实践包括为所有局部变量保留一个小范围。这是在 LVTI 存在之前就遵循的干净代码黄金规则之一。
此规则支持可读性和调试阶段。它可以加快查找错误和编写修复程序的过程。请考虑以下打破此规则的示例:
// Avoid
...
var stack = new Stack();
stack.push("John");
stack.push("Martin");
stack.push("Anghel");
stack.push("Christian");
// 50 lines of code that doesn't use stack
// John, Martin, Anghel, Christian
stack.forEach(...);
因此,前面的代码声明了一个具有四个名称的栈,包含 50 行不使用此栈的代码,并通过forEach()
方法完成此栈的循环。此方法继承自java.util.Vector
,将栈作为任意向量(John
、Martin
、Anghel
、Christian
循环。这是我们想要的遍历顺序。
但后来,我们决定从栈切换到ArrayDeque
(原因无关紧要)。这次,forEach()
方法将是由ArrayDeque
类提供的方法。此方法的行为不同于Vector.forEach()
,即循环将遍历后进先出 (LIFO )遍历(Christian
、Anghel
、Martin
、John
之后的条目:
// Avoid
...
var stack = new ArrayDeque();
stack.push("John");
stack.push("Martin");
stack.push("Anghel");
stack.push("Christian");
// 50 lines of code that doesn't use stack
// Christian, Anghel, Martin, John
stack.forEach(...);
这不是我们的本意!我们切换到ArrayDeque
是为了其他目的,而不是为了影响循环顺序。但是很难看出代码中有 bug,因为包含forEach()
部分的代码部分不在我们完成修改的代码附近(代码行下面 50 行)。我们有责任提出一个解决方案,最大限度地提高快速修复这个 bug 的机会,避免一堆上下滚动来了解正在发生的事情。解决方案包括遵循我们之前调用的干净代码规则,并使用小范围的stack
变量编写此代码:
// Prefer
...
var stack = new Stack();
stack.push("John");
stack.push("Martin");
stack.push("Anghel");
stack.push("Christian");
// John, Martin, Anghel, Christian
stack.forEach(...);
// 50 lines of code that doesn't use stack
现在,当我们从Stack
切换到ArrayQueue
时,我们应该更快地注意到错误并能够修复它。
88 LVTI 与三元运算符
只要写入正确,三元 运算符允许我们在右侧使用不同类型的操作数。例如,以下代码将不会编译:
// Does not compile
List evensOrOdds = containsEven ?
List.of(10, 2, 12) : Set.of(13, 1, 11);
// Does not compile
Set evensOrOdds = containsEven ?
List.of(10, 2, 12) : Set.of(13, 1, 11);
但是,可以通过使用正确/支持的显式类型重写代码来修复此代码:
Collection evensOrOdds = containsEven ?
List.of(10, 2, 12) : Set.of(13, 1, 11);
Object evensOrOdds = containsEven ?
List.of(10, 2, 12) : Set.of(13, 1, 11);
对于以下代码片段,类似的尝试将失败:
// Does not compile
int numberOrText = intOrString ? 2234 : "2234";
// Does not compile
String numberOrText = intOrString ? 2234 : "2234";
但是,可以这样修复:
Serializable numberOrText = intOrString ? 2234 : "2234";
Object numberOrText = intOrString ? 2234 : "2234";
因此,为了在右侧有一个具有不同类型操作数的三元运算符,开发人员必须匹配支持两个条件分支的正确类型。或者,开发人员可以依赖 LVTI,如下所示(当然,这也适用于相同类型的操作数):
// inferred type, Collection
var evensOrOddsCollection = containsEven ?
List.of(10, 2, 12) : Set.of(13, 1, 11);
// inferred type, Serializable
var numberOrText = intOrString ? 2234 : "2234";
不要从这些例子中得出结论,var
类型是在运行时推断出来的!不是的!
89 LVTI 和for
循环
使用显式类型声明简单的for
循环是一项琐碎的任务,如下所示:
// explicit type
for (int i = 0; i < 5; i++) {
...
}
或者,我们可以使用增强的for
循环:
List players = List.of(
new Player(), new Player(), new Player());
for (Player player: players) {
...
}
从 JDK10 开始,我们可以将变量的显式类型i
和player
替换为var
,如下所示:
for (var i = 0; i < 5; i++) { // i is inferred of type int
...
}
for (var player: players) { // i is inferred of type Player
...
}
当循环数组、集合等的类型发生更改时,使用var
可能会有所帮助。例如,通过使用var
,可以在不指定显式类型的情况下循环以下array
的两个版本:
// a variable 'array' representing an int[]
int[] array = { 1, 2, 3 };
// or the same variable, 'array', but representing a String[]
String[] array = {
"1", "2", "3"
};
// depending on how 'array' is defined
// 'i' will be inferred as int or as String
for (var i: array) {
System.out.println(i);
}
90 LVTI 和流
让我们考虑以下Stream
流:
// explicit type
Stream numbers = Stream.of(1, 2, 3, 4, 5);
numbers.filter(t -> t % 2 == 0).forEach(System.out::println);
使用 LVTI 代替Stream
非常简单。只需将Stream
替换为var
,如下所示:
// using var, inferred as Stream
var numberStream = Stream.of(1, 2, 3, 4, 5);
numberStream.filter(t -> t % 2 == 0).forEach(System.out::println);
下面是另一个例子:
// explicit types
Stream paths = Files.lines(Path.of("..."));
List files = paths.map(p -> new File(p)).collect(toList());
// using var
// inferred as Stream
var pathStream = Files.lines(Path.of(""));
// inferred as List
var fileList = pathStream.map(p -> new File(p)).collect(toList());
看起来 Java10、LVTI、Java8 和Stream
API 是一个很好的团队。
91 使用 LVTI 分解嵌套/大型表达式链
大型/嵌套表达式通常是一些代码片段,它们看起来非常令人印象深刻,令人生畏。它们通常被视为智能 或智慧 代码的片段。关于这是好是坏是有争议的,但最有可能的是,这种平衡倾向于有利于那些声称应该避免这种代码的人。例如,检查以下表达式:
List ints = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// Avoid
int result = ints.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values()
.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList())
.stream()
.mapToInt(Integer::intValue)
.sum();
这样的表达式可以是有意编写的,也可以表示一个增量过程的最终结果,该过程在时间上丰富了一个最初很小的表达式。然而,当这些表达式开始成为可读性的空白时,它们必须通过局部变量被分解成碎片。但这并不有趣,可以被认为是我们想要避免的令人筋疲力尽的工作:
List ints = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// Prefer
Collection> evenAndOdd = ints.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values();
List evenOrOdd = evenAndOdd.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList());
int sumEvenOrOdd = evenOrOdd.stream()
.mapToInt(Integer::intValue)
.sum();
检查前面代码中局部变量的类型。我们有Collection>
、List
和int
。很明显,这些显式类型需要一些时间来获取和写入。这可能是避免将此表达式拆分为碎片的一个很好的理由。然而,如果我们希望采用局部变量的样式,那么使用var
类型而不是显式类型的琐碎性是很诱人的,因为它节省了通常用于获取显式类型的时间:
var intList = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// Prefer
var evenAndOdd = intList.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values();
var evenOrOdd = evenAndOdd.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList());
var sumEvenOrOdd = evenOrOdd.stream()
.mapToInt(Integer::intValue)
.sum();
令人惊叹的!现在,编译器的任务是推断这些局部变量的类型。我们只选择打破表达的点,用var
来划分。
92 LVTI 和方法返回值和参数类型
根据经验,LVTI 不能用作return
方法类型或参数方法类型;相反,var
类型的变量可以作为方法参数传递或存储return
方法。让我们通过几个例子来迭代这些语句:
// Does not compile
public var fetchReport(Player player, Date timestamp) {
return new Report();
}
public Report fetchReport(var player, var timestamp) {
return new Report();
}
var
类型的变量可以作为方法参数传递,也可以存储一个返回方法。下面的代码编译成功并且可以工作:
public Report checkPlayer() {
var player = new Player();
var timestamp = new Date();
var report = fetchReport(player, timestamp);
return report;
}
public Report fetchReport(Player player, Date timestamp) {
return new Report();
}
93 LVTI 和匿名类
LVTI 可以用于匿名类。下面是一个匿名类的示例,该类对weighter
变量使用显式类型:
public interface Weighter {
int getWeight(Player player);
}
Weighter weighter = new Weighter() {
@Override
public int getWeight(Player player) {
return ...;
}
};
Player player = ...;
int weight = weighter.getWeight(player);
现在,看看如果我们使用 LVTI 会发生什么:
var weighter = new Weighter() {
@Override
public int getWeight(Player player) {
return ...;
}
};
94 LVTI 可以是最终的,也可以是有效最终的
作为一个快速提醒,从 JavaSE8 开始,一个局部类可以访问封闭块的局部变量和参数,这些变量和参数是final
或实际上是final
。一个变量或参数,其值在初始化后从未改变,实际上是最终的 。
下面的代码片段表示一个有效最终 变量(尝试重新分配ratio
变量将导致错误,这意味着该变量是有效最终 )和两个final
变量(尝试重新分配limit
和bmi
变量将导致错误)的用例在一个错误中,这意味着这些变量是final
:
public interface Weighter {
float getMarginOfError();
}
float ratio = fetchRatio(); // this is effectively final
var weighter = new Weighter() {
@Override
public float getMarginOfError() {
return ratio * ...;
}
};
ratio = fetchRatio(); // this reassignment will cause error
public float fetchRatio() {
final float limit = new Random().nextFloat(); // this is final
final float bmi = 0.00023f; // this is final
limit = 0.002f; // this reassignment will cause error
bmi = 0.25f; // this reassignment will cause error
return limit * bmi / 100.12f;
}
现在,让我们用var
替换显式类型。编译器将推断出这些变量(ratio
、limit
和bmi
的正确类型并保持它们的状态-ratio
将是有效最终 ,而limit
和bmi
是final
。尝试重新分配其中任何一个将导致特定错误:
var ratio = fetchRatio(); // this is effectively final
var weighter = new Weighter() {
@Override
public float getMarginOfError() {
return ratio * ...;
}
};
ratio = fetchRatio(); // this reassignment will cause error
public float fetchRatio() {
final var limit = new Random().nextFloat(); // this is final
final var bmi = 0.00023f; // this is final
limit = 0.002f; // this reassignment will cause error
bmi = 0.25f; // this reassignment will cause error
return limit * bmi / 100.12f;
}
95 LVTI 和 Lambda
使用 LVTI 和 Lambda 的问题是无法推断具体类型。不允许使用 Lambda 和方法引用初始化器 。此语句是var
限制的一部分;因此,Lambda 表达式和方法引用需要显式的目标类型。
例如,以下代码片段将不会编译:
// Does not compile
// lambda expression needs an explicit target-type
var incrementX = x -> x + 1;
// method reference needs an explicit target-type
var exceptionIAE = IllegalArgumentException::new;
由于var
不能使用,所以这两段代码需要编写如下:
Function incrementX = x -> x + 1;
Supplier exceptionIAE
= IllegalArgumentException::new;
但是在 Lambda 的上下文中,Java11 允许我们在 Lambda 参数中使用var
。例如,下面的代码在 Java11 中工作(更多详细信息可以在《JEP323:Lambda 参数的局部变量语法》 中找到:
@FunctionalInterface
public interface Square {
int calculate(int x);
}
Square square = (var x) -> x * x;
但是,请记住,以下操作不起作用:
var square = (var x) -> x * x; // cannot infer
96 LVTI 和null
初始化器、实例变量和catch
块变量
LVTI 与null
初始化器 、实例变量和catch
块变量有什么共同点?嗯,LVTI 不能和它们一起使用。以下尝试将失败:
// result in an error of type: variable initializer is 'null'
var message = null;
// result in: cannot use 'var' on variable without initializer
var message;
public class Player {
private var age; // error: 'var' is not allowed here
private var name; // error: 'var' is not allowed here
...
}
try {
TimeUnit.NANOSECONDS.sleep(1000);
} catch (var ex) { ... }
资源尝试使用
另一方面,var
类型非常适合资源尝试使用 ,如下例所示:
// explicit type
try (PrintWriter writer = new PrintWriter(new File("welcome.txt"))) {
writer.println("Welcome message");
}
// using var
try (var writer = new PrintWriter(new File("welcome.txt"))) {
writer.println("Welcome message");
}
97 LVTI 和泛型类型,T
为了理解 LVTI 如何与泛型类型相结合,让我们从一个示例开始。以下方法是泛型类型T
的经典用例:
public static T add(T t) {
T temp = t;
...
return temp;
}
在这种情况下,我们可以将T
替换为var
,代码将正常工作:
public static T add(T t) {
var temp = t;
...
return temp;
}
因此,具有泛型类型的局部变量可以利用 LVTI。让我们看看其他一些示例,首先使用泛型类型T
:
public T add(T t) {
List numberList = new ArrayList();
numberList.add(t);
numberList.add((T) Integer.valueOf(3));
numberList.add((T) Double.valueOf(3.9));
// error: incompatible types: String cannot be converted to T
// numbers.add("5");
return numberList.get(0);
}
现在,我们将List
替换为var
:
public T add(T t) {
var numberList = new ArrayList();
numberList.add(t);
numberList.add((T) Integer.valueOf(3));
numberList.add((T) Double.valueOf(3.9));
// error: incompatible types: String cannot be converted to T
// numbers.add("5");
return numberList.get(0);
}
注意并仔细检查ArrayList
实例化是否存在T
。不要这样做(这将被推断为ArrayList,并将忽略泛型类型T
后面的实际类型):
var numberList = new ArrayList<>();
98 LVTI、通配符、协变和逆变
用 LVTI 替换通配符、协变和逆变是一项微妙的工作,应该在充分意识到后果的情况下完成。
LVTI 和通配符
首先,我们来讨论 LVTI 和通配符(?
。通常的做法是将通配符与Class
关联,并编写如下内容:
// explicit type
Class clazz = Long.class;
在这种情况下,使用var
代替Class
没有问题。根据右边的类型,编译器将推断出正确的类型。在本例中,编译器将推断出Class
。
但是请注意,用 LVTI 替换通配符应该小心,并且您应该意识到其后果(或副作用)。让我们看一个例子,用var
替换通配符是一个错误的选择。考虑以下代码:
Collection stuff = new ArrayList<>();
stuff.add("hello"); // compile time error
stuff.add("world"); // compile time error
由于类型不兼容,此代码无法编译。一种非常糟糕的方法是用var
替换通配符来修复此代码,如下所示:
var stuff = new ArrayList<>();
strings.add("hello"); // no error
strings.add("world"); // no error
通过使用var
,错误将消失,但这不是我们在编写前面的代码(存在类型不兼容错误的代码)时想到的。所以,根据经验,不要仅仅因为一些恼人的错误会神奇地消失,就用var
代替Foo
!试着思考一下预期的任务是什么,并相应地采取行动。例如,可能在前面的代码片段中,我们试图定义ArrayList
,但由于错误,最终得到了Collection
。
LVTI 和协变/逆变
用 LVTI 替换协变(Foo
)或逆变(Foo
)是一种危险的方法,应该避免。
请查看以下代码片段:
// explicit types
Class intNumber = Integer.class;
Class fileReader = Reader.class;
在协变中,我们有一个上界,由Number
类表示,而在逆变中,我们有一个下界,由FilterReader
类表示。有了这些边界(或约束),以下代码将触发特定的编译时错误:
// Does not compile
// error: Class cannot be converted
// to Class
Class intNumber = Reader.class;
// error: Class cannot be converted
// to Class
Class fileReader = Integer.class;
现在,让我们用var
代替前面的协变和逆变:
// using var
var intNumber = Integer.class;
var fileReader = Reader.class;
此代码不会导致任何问题。现在,我们可以将任何类赋给这些变量,这样我们的边界/约束就消失了。这不是我们打算做的:
// this will compile just fine
var intNumber = Reader.class;
var fileReader = Integer.class;
所以,用var
代替协变和逆变是个错误的选择!
总结
这是本章的最后一个问题。请看《JEP323:Lambda 参数的局部变量语法》 、《JEP301:增强枚举》 了解更多信息。只要您熟悉本章介绍的问题,采用这些特性应该是相当顺利的。
从本章下载应用以查看结果和其他详细信息。
你可能感兴趣的:(java)
优先级队列 PriorityQueue 模拟实现
a添砖Java
java 开发语言
文章目录概要整体架构流程小结概要优先级队列实际是小堆,根据不同的比较方法实现小堆,也可以根据自己的需要重写比较方法,从而实现自己想要的优先级队列,获取想要的数据,接下来将会用整数模拟实现一个优先级队列;这里我的优先是优先获取最小的元素,保证出队的永远是现存的数据里最小的;整体架构流程packagedom.bite;importjava.util.Arrays;publicclassPriority
Vue.js 新手必看:5个趣味小案例快速理解数据绑定原理
云资社
VUE vue.js 前端 javascript
Vue.js是一个渐进式JavaScript框架,用于构建用户界面。其核心特性之一是数据绑定,它允许开发者通过简单的声明式语法将数据与DOM元素绑定在一起。这种双向数据绑定机制使得数据更新和视图更新变得非常直观和高效。本文将通过5个趣味小案例,帮助Vue.js新手快速理解数据绑定的原理和实现方式。案例1:简单的文本绑定目标将输入框中的内容实时显示在页面上。实现代码Vue数据绑定-文本绑定输入框内容
Redisson分布式锁和同步器完整篇
高锰酸钾_
分布式 java redis redisson
Redisson分布式锁和同步器完整篇在分布式系统中,如何确保多个服务实例之间的数据一致性和资源协调是一个关键挑战。Redisson作为基于Redis的Java客户端,提供了一套完整的分布式锁和同步器解决方案,帮助开发者轻松应对这些挑战。本文将深入探讨Redisson的核心组件,包括:分布式锁:可重入锁、公平锁、读写锁、红锁、联锁同步工具:信号量、可过期信号量、闭锁我们将从以下维度展开详细分析:✅
Spring Boot中使用RabbitMQ(2)
D1561691
程序员 java-rabbitmq spring boot rabbitmq
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!MessageBroker与AMQP简介MessageBroker是一种消息验证、传输、路由的架构模式,其设计目标主要应用于下面这些场景:消息路由到一个或多个目的地消息转化为其他的表现方式执行消息的聚集、消息的分解,并将结果发送到他们的目的地,然后重新组合相应返回给消息用户调用Web服务来检索数据响
Java集合核心详解【十分钟带你了解整个集合体系】
小小怪下士yeah
Java集合核心知识点 开发语言 java 数据结构 算法 链表
前言:集合是Java中非常重要的一章,学习难度也相对较大,不会很快就能掌握,这里我们先对集合框架有一个大概的了解,记住其中的基础知识,后面深入研究某一个集合时,才能更好的掌握。文章目录一、集合介绍二、集合与数组的区别三、集合框架图四、Collection详解图五、Map详解一、集合是什么?Java是面向对象的语言,一般我们在编程的时候自然需要存储对象的容器,数组可以满足这个需求,但是数组初始化时长
Mongodb主从模式最佳方案
Christian Bai
mongodb 数据库
我整理的一些关于【Java】的项目学习资料(附讲解~~)和大家一起分享、学习一下:https://d.51cto.com/bLN8S1MongoDB主从模式最佳方案MongoDB是一款开源的文档型数据库,被广泛应用于许多现代应用中。其强大的性能和灵活的数据结构使得它特别适合处理大数据和高并发访问。本文将介绍MongoDB的主从模式,并提供最佳方案和示例代码,帮助你更好地理解这种模式的运作原理。什么
java获取服务器状态_获取远程服务器上 Java 进程的运行状态
夏种子
java获取服务器状态
为了安全考虑,有些服务器会被限制登录.本文介绍如何获取远程服务器上Java进程的运行状态.启动jstatd服务在服务器端启动jstatd服务后,远程的机器可以通过rmi协议获取服务器上Java程序的运行状态.在服务器上创建jstatd的授权文件,假设文件路径为/etc/jstatd.all.policy,内容如下:grantcodebase"file:/usr/local/java/lib/too
面试官 :Java 调优经验有吗?
Think_Higher
Java生态圈 大中IT企业面试题整理 java 数据库 开发语言
文章目录调优准备性能分析CPU分析jstack[pid]jstat-gcutil[pid]vmstat15内存分析IO分析1.文件IO2.网络IO其他分析工具JavaMissionControl(jmc)BtraceJwebap性能调优CPU调优内存调优IO调优其他优化建议JVM参数进阶对于调优这个事情来说,一般就是三个过程:性能监控:问题没有发生,你并不知道你需要调优什么?此时需要一些系统、应用
Java 程序GC机制及性能稳定性调优分析
shines_m
性能测试 java jvm 开发语言 压力测试
一、JVM资源监控工具1.jvisualVM工具VisualVM提供了一个可视界面,能够监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象;在JDK_HOME/bin目录下,双击jvisualvm.exe文件即可打开运行。打开后默认会监控本地运行的java程序,运行的界面如下:2.连接远程服务器,需要在被监控JVM服务器上启动jstatd服务JVMjstatDaemon:守护进
Java GC性能分析与调优实战
wespten
全栈软件测试 人工智能测试开发 自动化测试 性能测试 Spring全家桶 微信小程序 Java全栈开发 jvm
一、JVMGC1、JVM线程简介在ThreadDump中,有一些JVM内部的后台线程来执行,譬如垃圾回收或者低内存的检测等等任务,这些线程往往在JVM初始化的时候就存在,如下所示:1.HotSpotVMThread被HotSpotVM管理的内部线程为了完成内部本地操作,一般来说不需要担心它们,除非CPU很高。"VMPeriodicTaskThread"prio=10tid=0xad909400ni
Java学习笔记
范梦迪
java 笔记
第一章Java基础1.HelloWorld程序publicclassHelloWorld{publicstaticvoidmain(String[]args){System.out.println("Hello,World!");}}2.数据类型Java提供了多种数据类型,包括基本数据类型和引用数据类型。基本数据类型用于存储简单的数据值,而引用数据类型用于存储对象的引用。2.1基本数据类型Java
go语言获取机器的进程和进程运行参数 获取当前进程的jmx端口 go调用/jstat获取当前Java进程gc情况
march of Time
go jvm golang java python
这里主要分享go中获取机器进程和进程参数的一些代码获取当前机器所有的pid:import"github.com/shirou/gopsutil/process"pids,err:=process.Pids()for_,pid:=rangepids{proc,err:=process.NewProcess(pid)iferr!=nil{log.Errorf("getpid%dinfoerror:%s
中科院空天院的面试题总结-Java
web18285997089
面试 学习路线 阿里巴巴 java 开发语言
JAVA1.谈谈ajax的异步请求,与同步请求的区别答:同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。自己说了一堆,面试官直接这两句回我,简洁明了,这就是功力,惭愧2.数据库中有成绩字段,给出查询排名前10的语句答:select*from(select*from表orderby成绩desc)
Java类的初始化执行顺序
stormkai
java java
文章目录Java类的初始化执行顺序1.无继承关系的类2.有继承关系的类3.总结Java类的初始化执行顺序1.无继承关系的类静态变量→静态代码块→非静态变量→非静态代码块→构造方法publicclassBase{staticinti=0;intj=0;{i++;j++;System.out.println("代码块i="+i+"\t实例代码块j="+j);}static{System.out.pri
【Java进阶篇】——第9篇:Lambda表达式与Stream API
猿享天开
Java开发从入门到精通 java 开发语言
第9篇:Lambda表达式与StreamAPIJava8引入的Lambda表达式和StreamAPI是函数式编程范式的核心特性,彻底改变了Java代码的编写方式。它们简化了集合操作、提升了代码可读性,并通过并行处理优化了性能。本文将从基础语法到实战应用,系统解析Lambda与Stream的核心概念,并结合实际案例展示其强大能力。1.Lambda表达式基础Lambda表达式本质上是一个匿名函数,用于
华为OD机试 - 特殊的加密算法 - 深度优先搜索DFS(Java 2024 D卷 200分)
哪 吒
华为od 深度优先 java
华为OD机试2024D卷题库疯狂收录中,刷题点这里专栏导读本专栏收录于《华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)》。刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。一、题目描述有一种特殊的加密算法,明文为一段数字串,经过密码本查找转换,生成另一段密文数字串。规则如下明文为一段数字串由0-9
vue3 ref/reactive 修改数组的方法
取啥好
vue vue.js javascript 前端
import{ref}from'vue'//给每个todo对象一个唯一的idletid=0constnewTodo=ref('')consttodos=ref([{id:id++,text:'LearnHTML'},{id:id++,text:'LearnJavaScript'},{id:id++,text:'LearnVue'}])functionaddTodo(){todos.value.pu
C#中的动态类型用法总结带演示代码
yuanpan
c# windows microsoft
在C#中,dynamic类型是一种特殊的类型,它允许你在编译时绕过类型检查,而是在运行时解析类型。这使得你可以编写更灵活的代码,但也增加了运行时错误的风险。dynamic类型通常用于与动态语言(如Python、JavaScript)交互,或者处理一些在编译时无法确定类型的场景。1.基本用法你可以使用dynamic关键字来声明一个动态类型的变量。这个变量在编译时不会进行类型检查,而是在运行时根据实际
如何在Java中处理异步操作中的异常?
北执南念
工作中总结加强学习 java
如何在Java中处理异步操作中的异常?文章目录如何在Java中处理异步操作中的异常?1.使用Future和ExecutorService2.使用CompletableFuture3.使用RxJava或ProjectReactor4.异步框架的特定异常处理在Java中处理异步操作中的异常是一个重要的任务,因为异步编程模型通常意味着异常不会像同步代码那样直接被抛出到调用栈中。处理异步操作中的异常通常涉
Hutool-------值得推荐的java工具库
丶Apache
Java
网址:https://www.hutool.cn/docs/#/安装Maven在项目的pom.xml的dependencies中加入以下内容:cn.hutoolhutool-all5.3.7Gradlecompile'cn.hutool:hutool-all:5.3.7'包含组件一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时
JavaIO编程二:字节流与字符流
嘵奇
JavaIO编程 java
知识流主要是指的数据的处理方式,以及目标内容的处理机制,所有的流部分分为输入流和输出流,在java.io包中针对输入流和输出流分为两种:字节操作流:OutputStream(字节输出流)、InputStream(字节输入流)字符操作流:Writer(字符输出流)、Reader(字符输入流)不管使用哪一种操作流,本质上的操作流程都是类似的:通过File类设定要操作的文件路径或者IP地址通过字节流或字
SAP_ABAP_MM_物料视图维护监控报表(自定义开发)
Terry谈企业数字化
Abap编程 SAP ABAP
SAPABAP顾问(开发工程师)能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读458次。目标:基于对SAPabap顾问能力模型的梳理,给一年左右经验的abaper快速成长为三年经验提供超级燃料!https://blog.csdn.net/java_zhong1990/article/details/1324699771应用场景,查询物料主数据维护情况,为物料维护及时性提供参考。2
Hutool-超级好用的Java工具类库
独往丶
Java工具库 java
官方网址:Hutool简介Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;Hutool是项目中“util”包友好的替代,它节省
JavaScript网页设计案例:动态天气预报页面
静默.\\
javascript 开发语言
在这个案例中,我们将创建一个简单的网页,该网页能够根据用户输入的城市名称显示当前的天气情况。这个项目不仅将帮助我们理解如何使用JavaScript进行DOM操作和事件处理,还将介绍如何通过API获取实时数据。1.准备工作首先,你需要注册一个免费的天气API服务(如OpenWeatherMap),以获取API密钥。这将允许你访问其服务器上的天气数据。2.HTML结构让我们从基本的HTML结构开始:D
解析浏览器中JavaScript与Native交互原理:以WebGPU为例
ttod_qzstudio
JavaScript JavaScript WebGPU
引言随着Web应用复杂度的提升,开发者对浏览器访问本地硬件能力的需求日益增长。然而,浏览器必须在开放性与安全性之间找到平衡——既不能放任JavaScript(JS)随意操作系统资源,又要为高性能计算、图形渲染等场景提供支持。WebGPU的出现正是这一矛盾的解决方案之一。作为新一代Web图形API,WebGPU允许JS以接近原生(Native)的方式操作GPU,同时严格遵循浏览器的安全模型。本文将结
Java查询es很慢怎么办_elasticsearch索引和搜索慢问题分析解决
股票期货软件开发
Java查询es很慢怎么办
简述Elasticsearch是一个分布式的免费开源搜索和分析引擎,能够实现近实时的数据搜索。在使用的过程中,由于各种原因可能导致集群写入或者查询缓慢,本文主要讲述集中常见的原因和解决方法。写入拒绝或者慢现象当像索引(存储和使文档可被搜索)或者搜索数据的时候会出现类似如下429状态码的报错:"status":429,"error":{"type":"es_rejected_execution_ex
java 知识点突击-(1-10)
栗子~~
面试突击(个人) java 面试 开发语言
文章目录前言java知识点扫盲目录java知识点突击-(1-10)01JDK、JRE、JVM什么区别02==和equals的区别03hashcode()与equals()的作用、区别和联系04重载和重写的区别05final的作用06为什么局部内部类和匿名内部类只能访问局部final变量?07String、StringBuffer,StringBuilder的区别?08String为什么是final
【Java基础-46】泛型在Java集合中的应用:提升代码安全性与可读性
AllenBright
# Java基础 java 开发语言
在Java编程中,集合(Collection)是一个非常重要的数据结构,用于存储和操作一组对象。然而,在Java5之前,集合中的元素都是Object类型,这意味着我们可以将任何类型的对象放入集合中,但在取出时需要进行强制类型转换。这种方式不仅容易引发ClassCastException,还降低了代码的可读性和安全性。为了解决这个问题,Java5引入了泛型(Generics)机制。泛型允许我们在定义
场景识别-音频场景
法迪
场景识别 音频事件 playback
目的避免管控正在使用音频的场景、同时定义黑名单音频使用APP列表是否正在播放音乐frameworks/base/services/core/java/com/android/server/audio/PlaybackActivityMonitor.javaPlaybackActivityMonitor进行playerEvent和releasePlayer事件进行埋点/***Updateplayer
Java面试突击3(3):Java基础面试--JVM
CodingALife
社招面经 java
1、JVM有哪⼏块内存区域?Java8之后对内存分代做什么改进?Version:0.9StartHTML:0000000105EndHTML:0000003884StartFragment:0000000141EndFragment:0000003844集合、并发、spring框架,期待着我对这些基础的东西做⼀些很深⼊的,很⽜X的讲解,基于框架写⼀些代码,完事⼉了之后,就会把代码进⾏⼀个部署,⼀般
对于规范和实现,你会混淆吗?
yangshangchuan
HotSpot
昨晚和朋友聊天,喝了点咖啡,由于我经常喝茶,很长时间没喝咖啡了,所以失眠了,于是起床读JVM规范,读完后在朋友圈发了一条信息:
JVM Run-Time Data Areas:The Java Virtual Machine defines various run-time data areas that are used during execution of a program. So
android 网络
百合不是茶
网络
android的网络编程和java的一样没什么好分析的都是一些死的照着写就可以了,所以记录下来 方便查找 , 服务器使用的是TomCat
服务器代码; servlet的使用需要在xml中注册
package servlet;
import java.io.IOException;
import java.util.Arr
[读书笔记]读法拉第传
comsci
读书笔记
1831年的时候,一年可以赚到1000英镑的人..应该很少的...
要成为一个科学家,没有足够的资金支持,很多实验都无法完成
但是当钱赚够了以后....就不能够一直在商业和市场中徘徊......
随机数的产生
沐刃青蛟
随机数
c++中阐述随机数的方法有两种:
一是产生假随机数(不管操作多少次,所产生的数都不会改变)
这类随机数是使用了默认的种子值产生的,所以每次都是一样的。
//默认种子
for (int i = 0; i < 5; i++)
{
cout<<
PHP检测函数所在的文件名
IT独行者
PHP 函数
很简单的功能,用到PHP中的反射机制,具体使用的是ReflectionFunction类,可以获取指定函数所在PHP脚本中的具体位置。 创建引用脚本。
代码:
[php]
view plain
copy
// Filename: functions.php
<?php&nbs
银行各系统功能简介
文强chu
金融
银行各系统功能简介 业务系统 核心业务系统 业务功能包括:总账管理、卡系统管理、客户信息管理、额度控管、存款、贷款、资金业务、国际结算、支付结算、对外接口等 清分清算系统 以清算日期为准,将账务类交易、非账务类交易的手续费、代理费、网络服务费等相关费用,按费用类型计算应收、应付金额,经过清算人员确认后上送核心系统完成结算的过程 国际结算系
Python学习1(pip django 安装以及第一个project)
小桔子
python django pip
最近开始学习python,要安装个pip的工具。听说这个工具很强大,安装了它,在安装第三方工具的话so easy!然后也下载了,按照别人给的教程开始安装,奶奶的怎么也安装不上!
第一步:官方下载pip-1.5.6.tar.gz, https://pypi.python.org/pypi/pip easy!
第二部:解压这个压缩文件,会看到一个setup.p
php 数组
aichenglong
PHP 排序 数组 循环 多维数组
1 php中的创建数组
$product = array('tires','oil','spark');//array()实际上是语言结构而不 是函数
2 如果需要创建一个升序的排列的数字保存在一个数组中,可以使用range()函数来自动创建数组
$numbers=range(1,10)//1 2 3 4 5 6 7 8 9 10
$numbers=range(1,10,
安装python2.7
AILIKES
python
安装python2.7
1、下载可从 http://www.python.org/进行下载#wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz
2、复制解压
#mkdir -p /opt/usr/python
#cp /opt/soft/Python-2
java异常的处理探讨
百合不是茶
JAVA异常
//java异常
/*
1,了解java 中的异常处理机制,有三种操作
a,声明异常
b,抛出异常
c,捕获异常
2,学会使用try-catch-finally来处理异常
3,学会如何声明异常和抛出异常
4,学会创建自己的异常
*/
//2,学会使用try-catch-finally来处理异常
getElementsByName实例
bijian1013
element
实例1:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/x
探索JUnit4扩展:Runner
bijian1013
java 单元测试 JUnit
参加敏捷培训时,教练提到Junit4的Runner和Rule,于是特上网查一下,发现很多都讲的太理论,或者是举的例子实在是太牵强。多搜索了几下,搜索到两篇我觉得写的非常好的文章。
文章地址:http://www.blogjava.net/jiangshachina/archive/20
[MongoDB学习笔记二]MongoDB副本集
bit1129
mongodb
1. 副本集的特性
1)一台主服务器(Primary),多台从服务器(Secondary)
2)Primary挂了之后,从服务器自动完成从它们之中选举一台服务器作为主服务器,继续工作,这就解决了单点故障,因此,在这种情况下,MongoDB集群能够继续工作
3)挂了的主服务器恢复到集群中只能以Secondary服务器的角色加入进来
2
【Spark八十一】Hive in the spark assembly
bit1129
assembly
Spark SQL supports most commonly used features of HiveQL. However, different HiveQL statements are executed in different manners:
1. DDL statements (e.g. CREATE TABLE, DROP TABLE, etc.)
Nginx问题定位之监控进程异常退出
ronin47
nginx在运行过程中是否稳定,是否有异常退出过?这里总结几项平时会用到的小技巧。
1. 在error.log中查看是否有signal项,如果有,看看signal是多少。
比如,这是一个异常退出的情况:
$grep signal error.log
2012/12/24 16:39:56 [alert] 13661#0: worker process 13666 exited on s
No grammar constraints (DTD or XML schema).....两种解决方法
byalias
xml
方法一:常用方法 关闭XML验证
工具栏:windows => preferences => xml => xml files => validation => Indicate when no grammar is specified:选择Ignore即可。
方法二:(个人推荐)
添加 内容如下
<?xml version=
Netty源码学习-DefaultChannelPipeline
bylijinnan
netty
package com.ljn.channel;
/**
* ChannelPipeline采用的是Intercepting Filter 模式
* 但由于用到两个双向链表和内部类,这个模式看起来不是那么明显,需要仔细查看调用过程才发现
*
* 下面对ChannelPipeline作一个模拟,只模拟关键代码:
*/
public class Pipeline {
MYSQL数据库常用备份及恢复语句
chicony
mysql
备份MySQL数据库的命令,可以加选不同的参数选项来实现不同格式的要求。
mysqldump -h主机 -u用户名 -p密码 数据库名 > 文件
备份MySQL数据库为带删除表的格式,能够让该备份覆盖已有数据库而不需要手动删除原有数据库。
mysqldump -–add-drop-table -uusername -ppassword databasename > ba
小白谈谈云计算--基于Google三大论文
CrazyMizzz
Google 云计算 GFS
之前在没有接触到云计算之前,只是对云计算有一点点模糊的概念,觉得这是一个很高大上的东西,似乎离我们大一的还很远。后来有机会上了一节云计算的普及课程吧,并且在之前的一周里拜读了谷歌三大论文。不敢说理解,至少囫囵吞枣啃下了一大堆看不明白的理论。现在就简单聊聊我对于云计算的了解。
我先说说GFS
&n
hadoop 平衡空间设置方法
daizj
hadoop balancer
在hdfs-site.xml中增加设置balance的带宽,默认只有1M:
<property>
<name>dfs.balance.bandwidthPerSec</name>
<value>10485760</value>
<description&g
Eclipse程序员要掌握的常用快捷键
dcj3sjt126com
编程
判断一个人的编程水平,就看他用键盘多,还是鼠标多。用键盘一是为了输入代码(当然了,也包括注释),再有就是熟练使用快捷键。 曾有人在豆瓣评
《卓有成效的程序员》:“人有多大懒,才有多大闲”。之前我整理了一个
程序员图书列表,目的也就是通过读书,让程序员变懒。 程序员作为特殊的群体,有的人可以这么懒,懒到事情都交给机器去做,而有的人又可以那么勤奋,每天都孜孜不倦得
Android学习之路
dcj3sjt126com
Android学习
转自:http://blog.csdn.net/ryantang03/article/details/6901459
以前有J2EE基础,接触JAVA也有两三年的时间了,上手Android并不困难,思维上稍微转变一下就可以很快适应。以前做的都是WEB项目,现今体验移动终端项目,让我越来越觉得移动互联网应用是未来的主宰。
下面说说我学习Android的感受,我学Android首先是看MARS的视
java 遍历Map的四种方法
eksliang
java HashMap java 遍历Map的四种方法
转载请出自出处:
http://eksliang.iteye.com/blog/2059996
package com.ickes;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
/**
* 遍历Map的四种方式
【精典】数据库相关相关
gengzg
数据库
package C3P0;
import java.sql.Connection;
import java.sql.SQLException;
import java.beans.PropertyVetoException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DBPool{
自动补全
huyana_town
自动补全
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml&quo
jquery在线预览PDF文件,打开PDF文件
天梯梦
jquery
最主要的是使用到了一个jquery的插件jquery.media.js,使用这个插件就很容易实现了。
核心代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.
ViewPager刷新单个页面的方法
lovelease
android viewpager tag 刷新
使用ViewPager做滑动切换图片的效果时,如果图片是从网络下载的,那么再子线程中下载完图片时我们会使用handler通知UI线程,然后UI线程就可以调用mViewPager.getAdapter().notifyDataSetChanged()进行页面的刷新,但是viewpager不同于listview,你会发现单纯的调用notifyDataSetChanged()并不能刷新页面
利用按位取反(~)从复合枚举值里清除枚举值
草料场
enum
以 C# 中的 System.Drawing.FontStyle 为例。
如果需要同时有多种效果,
如:“粗体”和“下划线”的效果,可以用按位或(|)
FontStyle style = FontStyle.Bold | FontStyle.Underline;
如果需要去除 style 里的某一种效果,
Linux系统新手学习的11点建议
刘星宇
编程 工作 linux 脚本
随着Linux应用的扩展许多朋友开始接触Linux,根据学习Windwos的经验往往有一些茫然的感觉:不知从何处开始学起。这里介绍学习Linux的一些建议。
一、从基础开始:常常有些朋友在Linux论坛问一些问题,不过,其中大多数的问题都是很基础的。例如:为什么我使用一个命令的时候,系统告诉我找不到该目录,我要如何限制使用者的权限等问题,这些问题其实都不是很难的,只要了解了 Linu
hibernate dao层应用之HibernateDaoSupport二次封装
wangzhezichuan
DAO Hibernate
/**
* <p>方法描述:sql语句查询 返回List<Class> </p>
* <p>方法备注: Class 只能是自定义类 </p>
* @param calzz
* @param sql
* @return
* <p>创建人:王川</p>
* <p>创建时间:Jul