ZetCode-Java-教程-三-
ZetCode Java 教程(三)
原文:ZetCode
Java 列出目录内容
原文:http://zetcode.com/articles/javalistdirectory/
Java 列表目录教程显示了如何以 Java 显示目录内容。
目录定义
目录是计算机文件系统中用于存储和定位文件的组织单位。 目录按层次结构组织成目录树。 目录具有亲子关系。
Java 列出目录的类
我们可以使用以下 Java 类列出目录内容:
java.nio.file.Files
org.apache.commons.io.FileUtils
java.io.File
使用Files.list
非递归列出目录内容
Files.list()
方法返回Path
对象的延迟填充流。 该列表不是递归的。
JavaFilesList.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class JavaFilesList {
public static void main(String[] args) throws IOException {
String dirName = "/home/janbodnar/prog/";
Files.list(new File(dirName).toPath())
.limit(10)
.forEach(path -> {
System.out.println(path);
});
}
}
本示例显示给定目录中的十个文件或目录。
使用Files.walk
递归列出目录内容
Files.walk()
方法通过遍历以给定起始文件为根的文件树来返回Paths
的延迟填充流。 Files.walk()
递归遍历所有子目录。
JavaFilesWalk.java
package com.zetcode;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class JavaFilesWalkFilter {
public static void main(String[] args) throws IOException {
try (Stream<Path> paths = Files.walk(Paths.get("/home/janbodnar/prog"))) {
paths.filter(Files::isRegularFile)
.forEach(System.out::println);
}
}
}
本示例使用Files.walk()
方法显示给定目录的内容。 使用filter()
方法,我们将目录的内容过滤为仅包含常规文件。
用 Apache Commons IO 列出目录内容
Apache commons 的FileUtils.listFiles()
允许递归和非递归列出目录内容。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
对于这个例子,我们需要这种依赖项。
JavaDirectoryContentsApacheCommons.java
package com.zetcode;
import java.io.File;
import java.util.List;
import org.apache.commons.io.FileUtils;
public class JavaDirectoryContentsApacheCommons {
public static void main(String[] args) {
String dirName = "/home/janbodnar/tmp/";
List<File> files = (List<File>) FileUtils.listFiles(new File(dirName), null, true);
files.forEach(System.out::println);
}
}
该代码示例使用FileUtils.listFiles()
递归显示目录内容。
List<File> files = (List<File>) FileUtils.listFiles(new File(dirName), null, true);
FileUtils.listFiles()
的第一个参数是要列出的目录名称。 第二个参数是应与列表匹配的扩展名数组。 如果给出null
,则返回所有文件。 第三个参数确定列表是否是递归的; 即,也搜索所有子目录。
使用Files.walkFileTree
非递归列出目录内容
Files.walkFileTree()
方法遍历以给定起始文件为根的文件树。 它使用FileVisitor
模式来指定遍历过程中关键点的必需行为:访问文件时,访问目录之前,访问目录之后或发生故障时。
JavaWalkFilesTree.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
public class JavaWalkFilesTree {
public static void main(String[] args) throws IOException {
String dirName = "/home/janbodnar/prog";
File file = new File(dirName);
Files.walkFileTree(file.toPath(), Collections.emptySet(), 1, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
}
该示例使用Files.walkFileTree()
非递归地遍历目录。
Files.walkFileTree(file.toPath(), Collections.emptySet(), 1, new SimpleFileVisitor<Path>() {
Files.walkFileTree()
参数是:起始文件,配置遍历的选项,要访问的最大目录级别数,为每个文件调用的文件访问者。 在我们的情况下,我们需要遍历一个目录级别。
使用Files.walkFileTree
递归列出目录内容
在下面的示例中,我们使用Files.walkFileTree()
遍历整个目录结构。
JavaWalkFilesTree.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class JavaWalkFilesTree {
public static void main(String[] args) throws IOException {
String dirName = "/home/janbodnar/prog";
File file = new File(dirName);
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
}
该示例使用重载的Files.walkFileTree()
方法来递归遍历目录。
使用File
非递归列出目录内容
java.io.File
类是一个较旧的 API,用于列出目录内容。 它没有前面提到的现代 API 强大。 File
的listFiles()
返回给定目录中的文件对象数组。
JavaDirectoryContentsFile.java
package com.zetcode;
import java.io.File;
public class JavaDirectoryContentsFile {
public static void main(String[] args) {
String dirName = "/home/janbodnar/tmp/";
File fileName = new File(dirName);
File[] fileList = fileName.listFiles();
for (File file: fileList) {
System.out.println(file);
}
}
}
该示例将给定目录的内容打印到控制台。 它不会进入子目录。
用File
递归列出目录内容
这次我们使用java.io.File
类递归列出目录。
JavaDirectoryContentsFileRecursive.java
package com.zetcode;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class JavaDirectoryContentsFileRecursive {
private static List<File> files = new ArrayList<>();
public static void main(String[] args) {
String dirName = "/home/janbodnar/tmp/";
File file = new File(dirName);
List<File> myfiles = doListing(file);
myfiles.forEach(System.out::println);
}
public static List<File> doListing(File dirName) {
File[] fileList = dirName.listFiles();
for (File file : fileList) {
if (file.isFile()) {
files.add(file);
} else if (file.isDirectory()) {
files.add(file);
doListing(file);
}
}
return files;
}
}
doListing()
方法列出目录的内容。 我们使用isDirectory()
方法确定文件是否为目录,然后在每个子目录上递归调用doListing()
。
在本教程中,我们展示了使用 Java 列出目录内容的各种方法。
您可能也对以下相关教程感兴趣:以 Java 读取文本文件, Java 附加到文件,以 Java 复制文件, Java 教程 ,用 Java8 的StringJoiner
连接字符串 ,Java 读取页面或 Google Guava 简介。
Java 附加到文件
原文:http://zetcode.com/articles/javaappendtofile/
Java 附加到文件教程显示了如何用 Java 附加到文件。 我们使用FileWriter
,FileOutputStream
,Files
,RandomAccessFile
,Google Guava 和 Apache Commons IO。
附加到文件通常在日志记录中使用。
在示例中,我们将文本附加到文件中。
towns.txt
Bratislava
Moldava
Košice
Trenčín
Prešov
Žilina
我们使用此文本文件。 它位于src/main/resources
目录中。
Java 使用FileWriter
附加到文件
FileWriter
类用于编写字符流。 FileWriter
采用可选的第二个参数:append
。 如果设置为true
,则数据将被写入文件末尾。
JavaAppendFileFileWriter.java
package com.zetcode;
import java.io.FileWriter;
import java.io.IOException;
public class JavaAppendFileFileWriter {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/towns.txt";
try (FileWriter fw = new FileWriter(fileName, true)) {
fw.append("Žilina\n");
}
}
}
本示例使用FileWriter
将数据附加到文件中。
Java 用FileOutputStream
附加到文件
FileOutputStream
是用于将数据写入File
或FileDescriptor
的输出流。 它带有一个可选的第二个参数,该参数确定是否将数据附加到文件中。
JavaAppendFileFileOutputStream.java
package com.zetcode;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class JavaAppendFileFileOutputStream {
public static void main(String[] args) throws FileNotFoundException, IOException {
String fileName = "src/main/resources/towns.txt";
byte[] tb = "Žilina\n".getBytes();
try (FileOutputStream fos = new FileOutputStream(fileName, true)) {
fos.write(tb);
}
}
}
本示例使用FileOutputStream
将数据附加到文件中。
Java 使用Files
附加到文件
Java 7 引入了java.nio.file.Files
类,该类可用于轻松地将数据附加到文件中。
JavaAppendFileFiles.java
package com.zetcode;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class JavaAppendFileFiles {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/towns.txt";
byte[] tb = "Žilina\n".getBytes();
Files.write(Paths.get(fileName), tb, StandardOpenOption.APPEND);
}
}
本示例将数据附加Files
。
Files.write(Paths.get(fileName), tb, StandardOpenOption.APPEND);
Files.write()
的第三个参数表明如何打开文件进行写入。 使用StandardOpenOption.APPEND
可以打开文件进行附加。
Java 用RandomAccessFile
附加到文件
RandomAccessFile
用于读取和写入随机访问文件。
JavaAppendFileRandomAccessFile.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class JavaAppendFileRandomAccessFile {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/towns.txt";
File file = new File(fileName);
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
long length = raf.length();
raf.setLength(length + 1);
raf.seek(raf.length());
raf.writeBytes("Žilina\n");
}
}
}
在此示例中,我们将数据附加RandomAccessFile
。
Java 用 Guava 附加到文件
我们可以使用 Guava 库将其附加到文件中。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>22.0</version>
</dependency>
我们需要这种 Guava 依赖。
JavaAppendFileGuava.java
package com.zetcode;
import com.google.common.base.Charsets;
import com.google.common.io.CharSink;
import com.google.common.io.FileWriteMode;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
public class JavaAppendFileGuava {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/towns.txt";
File file = new File(fileName);
CharSink chs = Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND);
chs.write("Žilina\n");
}
}
在示例中,我们使用 Guava 的CharSink
类将其附加到文件中。
CharSink chs = Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND);
Files.asCharSink()
的第三个参数指定文件写入模式; 使用FileWriteMode.APPEND
选项打开文件进行写入。
Java 使用 Apache Commons IO 附加到文件
在最后一个示例中,我们使用 Apache Commons IO 附加到文件。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
我们需要这种依赖项。
JavaAppendFileApacheCommons.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
public class JavaAppendFileApacheCommons {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/towns.txt";
File file = new File(fileName);
FileUtils.writeStringToFile(file, "Žilina", StandardCharsets.UTF_8, true);
}
}
我们使用FileUtils.writeStringToFile()
方法将其附加到文件中。 最后一个append
参数确定是否附加到文件。
在本教程中,我们展示了如何使用内置工具和第三方库在 Java 中附加文件。
您可能也对以下相关教程感兴趣: Java 教程, Java 列表目录内容, Java FileWriter
教程, Java 文件时间 ,用 Java8 的StringJoiner
连接字符串,Google Guava 简介,用 Java 过滤列表或 Android 教程。
Java ArrayList
教程
原文:http://zetcode.com/articles/javaarraylist/
Java ArrayList
教程显示了如何使用 Java 中的ArrayList
集合。 ArrayList
位于java.util
包中,是 Java 集合框架的重要集合。
Java 集合框架是用于表示和操作集合的统一架构,使集合可以独立于实现细节进行操作。 集合是代表一组对象的对象。
Java ArrayList
ArrayList
是元素的有序序列。 它是动态的并且可调整大小。 它提供对元素的随机访问。 随机访问意味着我们可以在恒定时间抓取任何元素。 添加数据后,ArrayList
会自动扩展。 与简单数组不同,ArrayList
可以保存多种数据类型的数据。 它允许所有元素,包括null
。
ArrayList
中的元素通过整数索引访问。 索引从零开始。 在ArrayList
的末尾元素的索引以及插入和删除需要固定的时间。
ArrayList
实例具有容量。 容量是用于在列表中存储元素的数组的大小。 当元素添加到ArrayList
时,其容量会自动增长。 选择适当的容量可以节省一些时间。
Java ArrayList
添加单个项目
可以使用add()
方法将单个元素添加到ArrayList
。
com/zetcode/ListAddItem.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class ListAddItem {
public static void main(String[] args) {
List<String> langs = new ArrayList<>();
langs.add("Java");
langs.add("Python");
langs.add(1, "C#");
langs.add(0, "Ruby");
for (String lang : langs) {
System.out.printf("%s ", lang);
}
System.out.println();
}
}
该示例将元素逐一添加到数组列表中。
List<String> langs = new ArrayList<>();
创建一个ArrayList
。 在菱形括号(<>
)中指定的数据类型将元素限制为该数据类型。 在我们的例子中,我们有一个字符串列表。
langs.add("Java");
使用add()
方法将元素添加到列表的末尾。
langs.add(1, "C#");
这次,重载的add()
方法将元素插入指定位置; "C#"
字符串将位于列表的第二个位置; 请记住,ArrayList
是元素的有序序列。
for (String lang : langs) {
System.out.printf("%s ", lang);
}
通过for
循环,我们浏览ArrayList
列表并打印其元素。
Ruby Java C# Python
这是输出。 请注意,元素保持插入顺序。
Java 列表
从 Java 9 开始,我们有几种工厂方法来创建包含少量元素的列表。 创建的列表是不可变的。
com/zetcode/ListOf.java
package com.zetcode;
import java.util.List;
public class ListOf {
public static void main(String[] args) {
var words = List.of("wood", "forest", "falcon", "eagle");
System.out.println(words);
var values = List.of(1, 2, 3);
System.out.println(values);
}
}
在示例中,我们创建了两个包含四个和三个元素的列表。
Java ArrayList get()
和size()
get()
返回此列表中指定位置的元素,size()
返回列表的大小。
com/zetcode/GetAndSizeEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class GetAndSizeEx {
public static void main(String[] args) {
List<String> colours = new ArrayList<>();
colours.add("blue");
colours.add("orange");
colours.add("red");
colours.add("green");
String col = colours.get(1);
System.out.println(col);
int size = colours.size();
System.out.printf("The size of the ArrayList is: %d%n", size );
}
}
该示例使用了ArrayList
的get()
和size()
方法
String col = colours.get(1);
get()
方法返回第二个元素,即"orange"
。
int size = colours.size();
size()
方法确定colours
列表的大小; 我们有四个要素。
orange
The size of the ArrayList is: 4
这是示例的输出。
Java ArrayList
复制
可以使用List.copy()
方法生成列表的副本。
com/zetcode/ListCopy.java
package com.zetcode;
import java.util.List;
public class ListCopy {
public static void main(String[] args) {
var words = List.of("forest", "wood", "eagle", "sky", "cloud");
System.out.println(words);
var words2 = List.copyOf(words);
System.out.println(words2);
}
}
该示例使用List.copy()
创建列表的副本。
原始ArrayList
ArrayList
可以包含各种数据类型。 这些称为原始列表。
注意:通常不建议使用原始列表。
原始列表通常需要强制转换,而且类型安全。
com/zetcode/DataTypesEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
class Base {}
enum Level {
EASY,
MEDIUM,
HARD
}
public class DataTypesEx {
public static void main(String[] args) {
Level level = Level.EASY;
List da = new ArrayList();
da.add("Java");
da.add(3.5);
da.add(55);
da.add(new Base());
da.add(level);
for (Object el : da) {
System.out.println(el);
}
}
}
该示例将五种不同的数据类型添加到数组列表中-字符串,双精度型,整数,对象和枚举。
List da = new ArrayList();
当我们将多个数据类型添加到列表时,我们省略了尖括号。
Java
3.5
55
com.zetcode.Base@659e0bfd
EASY
这是输出。
Java ArrayList
添加多个元素
下面的示例使用addAll()
方法一步将多个元素添加到列表中。
com/zetcode/AddingMultipleItemsEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class AddingMultipleItemsEx {
public static void main(String[] args) {
List<String> colours1 = new ArrayList<>();
colours1.add("blue");
colours1.add("red");
colours1.add("green");
List<String> colours2 = new ArrayList<>();
colours2.add("yellow");
colours2.add("pink");
colours2.add("brown");
List<String> colours3 = new ArrayList<>();
colours3.add("white");
colours3.add("orange");
colours3.addAll(colours1);
colours3.addAll(2, colours2);
for (String col : colours3) {
System.out.println(col);
}
}
}
创建两个列表。 稍后,使用addAll()
方法将列表中的元素添加到第三个列表中。
colours3.addAll(colours1);
addAll()
方法将所有元素添加到列表的末尾。
colours3.addAll(2, colours2);
此重载方法添加了从指定位置开始的所有元素。
white
orange
yellow
pink
brown
blue
red
green
This is the output of the example.
Java ArrayList
修改元素
下一个示例使用方法来修改ArrayList
。
com/zetcode/ModifyingListEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class ModifyingListEx {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
fillList(items);
items.set(3, "watch");
items.add("bowl");
items.remove(0);
items.remove("pen");
for (Object el : items) {
System.out.println(el);
}
items.clear();
if (items.isEmpty()) {
System.out.println("The list is empty");
} else {
System.out.println("The list is not empty");
}
}
public static void fillList(List<String> list) {
list.add("coin");
list.add("pen");
list.add("pencil");
list.add("clock");
list.add("book");
list.add("spectacles");
list.add("glass");
}
}
使用set()
,add()
,remove()
和clear()
方法创建和修改ArrayList
。
items.set(3, "watch");
set()
方法将第四个元素替换为"watch"
项。
items.add("bowl");
add()
方法在列表的末尾添加一个新元素。
items.remove(0);
remove()
方法删除索引为 0 的第一个元素。
items.remove("pen");
重载的remove()
方法删除"pen"
项的第一次出现。
items.clear();
clear()
方法从列表中删除所有元素。
if (items.isEmpty()) {
isEmpty()
方法确定列表是否为空。
pencil
watch
book
spectacles
glass
bowl
The list is empty
This is the output of the example.
Java ArrayList removeIf
removeIf()
方法删除满足给定谓词的集合中的所有元素。
com/zetcode/RemoveIfEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class RemoveIfEx {
public static void main(String[] args) {
List<Integer> values = new ArrayList<>();
values.add(5);
values.add(-3);
values.add(2);
values.add(8);
values.add(-2);
values.add(6);
values.removeIf(val -> val < 0);
System.out.println(values);
}
}
在我们的示例中,我们有一个ArrayList
整数。 我们使用removeIf
方法删除所有负值。
values.removeIf(val -> val < 0);
所有负数将从数组列表中删除。
[5, 2, 8, 6]
这是输出。
Java ArrayList removeAll
removeAll()
方法从该列表中删除指定集合中包含的所有其元素。 请注意,所有元素都已通过clear()
删除。
com/zetcode/RemoveAll.java
package com.zetcode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RemoveAll {
public static void main(String[] args) {
List<String> letters = new ArrayList<>();
letters.add("a");
letters.add("b");
letters.add("c");
letters.add("a");
letters.add("d");
System.out.println(letters);
letters.removeAll(Collections.singleton("a"));
System.out.println(letters);
}
}
在示例中,我们从列表中删除了所有"a"
字母。
Java ArrayList replaceAll
replaceAll()
方法用将运算符应用于该元素的结果替换列表的每个元素。
com/zetcode/ReplaceAllEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.function.UnaryOperator;
public class ReplaceAllEx {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("coin");
items.add("pen");
items.add("cup");
items.add("notebook");
items.add("class");
UnaryOperator<String> uo = (x) -> x.toUpperCase();
items.replaceAll(uo);
System.out.println(items);
}
}
该示例在每个列表元素上应用了一个运算符。 元素的字母转换为大写。
UnaryOperator<String> uo = (x) -> x.toUpperCase();
创建将字母转换为大写的UnaryOperator
。
items.replaceAll(uo);
使用replaceAll()
方法将运算符应用于列表元素。
[COIN, PEN, CUP, NOTEBOOK, CLASS]
这是输出。
第二个示例使用replaceAll()
方法将字符串项目大写。
com/zetcode/ReplaceAllEx2.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.function.UnaryOperator;
class MyOperator<T> implements UnaryOperator<String> {
@Override
public String apply(String var) {
if (var == null || var.length() == 0) {
return var;
}
return var.substring(0, 1).toUpperCase() + var.substring(1);
}
}
public class ReplaceAllEx2 {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("coin");
items.add("pen");
items.add("cup");
items.add("notebook");
items.add("glass");
items.replaceAll(new MyOperator<>());
System.out.println(items);
}
}
我们有一个字符串项目列表。 这些项目在replaceAll()
方法的帮助下大写。
class MyOperator<T> implements UnaryOperator<String> {
创建自定义UnaryOperator
。
@Override
public String apply(String var) {
if (var == null || var.length() == 0) {
return var;
}
return var.substring(0, 1).toUpperCase() + var.substring(1);
}
在UnaryOperator
的apply()
方法中,我们使用第一个大写字母还原字符串。
items.replaceAll(new MyOperator<>());
将运算符应用于列表项。
[Coin, Pen, Cup, Notebook, Glass]
This is the output of the example.
Java ArrayList.contains()
如果列表包含指定的元素,则contains()
方法返回true
。
com/zetcode/ContainsEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class ContainsEx {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("coin");
items.add("pen");
items.add("cup");
items.add("notebook");
items.add("class");
String item = "pen";
if (items.contains(item)) {
System.out.printf("There is a %s in the list%n", item);
}
}
}
该示例检查指定的项目是否在列表中。
if (items.contains(item)) {
System.out.printf("There is a %s in the list%n", item);
}
如果该项目在列表中,则会打印该消息。
There is a pen in the list
这是输出。
获取ArrayList
中元素的索引
ArrayList
中的每个元素都有其自己的索引号。 indexOf()
返回指定元素首次出现的索引,如果列表不包含该元素,则返回 -1。 lasindexOf()
返回指定元素最后一次出现的索引;如果列表中不包含该元素,则返回 -1。
com/zetcode/GetIndexEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class GetIndexEx {
public static void main(String[] args) {
List<String> colours = new ArrayList<>();
colours.add(0, "blue");
colours.add(1, "orange");
colours.add(2, "red");
colours.add(3, "green");
colours.add(4, "orange");
int idx1 = colours.indexOf("orange");
System.out.println(idx1);
int idx2 = colours.lastIndexOf("orange");
System.out.println(idx2);
}
}
该示例打印"orange"
元素的第一个和最后一个索引。
1
4
这是示例输出。
Java 列表的列表
We can add other lists into a list.
com/zetcode/ListOfLists.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class ListOfLists {
public static void main(String[] args) {
List<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
List<Integer> l2 = new ArrayList<>();
l2.add(4);
l2.add(5);
l2.add(6);
List<Integer> l3 = new ArrayList<>();
l3.add(7);
l3.add(8);
l3.add(9);
List<List<Integer>> nums = new ArrayList<>();
nums.add(l1);
nums.add(l2);
nums.add(l3);
System.out.println(nums);
for (List<Integer> list : nums) {
for (Integer n : list) {
System.out.printf("%d ", n);
}
System.out.println();
}
}
}
该示例创建三个整数列表。 以后,这些列表将添加到另一个第四列表中。
List<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
将创建一个整数列表。
List<List> nums = new ArrayList<>();
nums.add(l1);
nums.add(l2);
nums.add(l3);
创建列表列表。
for (List<Integer> list : nums) {
for (Integer n : list) {
System.out.printf("%d ", n);
}
System.out.println();
}
我们使用两个for
循环遍历所有元素。
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1 2 3
4 5 6
7 8 9
这是程序的输出。
Java ArrayList
子列表
subList()
方法返回指定的fromIndex
(包括)和toIndex
(不包括)之间的列表部分的视图。 子列表中的更改将反映在原始列表中。
com/zetcode/SubListEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class SubListEx {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("coin");
items.add("pen");
items.add("cup");
items.add("notebook");
items.add("glass");
items.add("chair");
items.add("ball");
items.add("bowl");
List<String> items2 = items.subList(2, 5);
System.out.println(items2);
items2.set(0, "bottle");
System.out.println(items2);
System.out.println(items);
}
}
该示例从项目列表创建子列表。
List<String> items2 = items.subList(2, 5);
使用subList()
方法创建一个子列表。 它包含索引为 2、3 和 4 的项目。
items2.set(0, "bottle");
我们替换子列表的第一项; 修改也反映在原始列表中。
[cup, notebook, glass]
[bottle, notebook, glass]
[coin, pen, bottle, notebook, glass, chair, ball, bowl]
This is the output of the example.
Java ArrayList
遍历
在下面的示例中,我们展示了遍历ArrayList
的五种方法。
com/zetcode/TraversingArrayListEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class TraversingArrayListEx {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>();
nums.add(2);
nums.add(6);
nums.add(7);
nums.add(3);
nums.add(1);
nums.add(8);
for (int i = 0; i < nums.size(); i++) {
System.out.printf("%d ", nums.get(i));
}
System.out.println();
for (int num : nums) {
System.out.printf("%d ", num);
}
System.out.println();
int j = 0;
while (j < nums.size()) {
System.out.printf("%d ", nums.get(j));
j++;
}
System.out.println();
ListIterator<Integer> it = nums.listIterator();
while(it.hasNext()) {
System.out.printf("%d ", it.next());
}
System.out.println();
nums.forEach(e -> System.out.printf("%d ", e));
System.out.println();
}
}
在示例中,我们遍历具有for
循环,while
循环,迭代器和forEach()
构造的整数数组列表。
List<Integer> nums = new ArrayList<>();
nums.add(2);
nums.add(6);
nums.add(7);
nums.add(3);
nums.add(1);
nums.add(8);
我们创建了一个ArrayList
整数。
for (int i = 0; i < nums.size(); i++) {
System.out.printf("%d ", nums.get(i));
}
在这里,我们使用经典的for
循环遍历列表。
for (int num : nums) {
System.out.printf("%d ", num);
}
第二种方法使用 Java 5 中引入的增强for
循环。
int j = 0;
while (j < nums.size()) {
System.out.printf("%d ", nums.get(j));
j++;
}
第三种方式使用while
循环。
ListIterator<Integer> it = nums.listIterator();
while(it.hasNext()) {
System.out.printf("%d ", it.next());
}
这里,ListIterator
用于遍历列表。
nums.forEach(e -> System.out.printf("%d ", e));
最后,我们使用 Java8 中引入的forEach()
方法。
2 6 7 3 1 8
2 6 7 3 1 8
2 6 7 3 1 8
2 6 7 3 1 8
2 6 7 3 1 8
该示例使用各种技术将列表的元素打印到控制台。
Java ArrayList
排序
对ArrayList
进行分类有不同的浪费。
使用其sort
方法对ArrayList
进行排序
ArrayList
的sort()
方法根据由指定比较器引起的顺序对列表进行排序。
com/zetcode/ArrayListSortingEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Age: " + age + " Name: " + name;
}
}
public class ArrayListSortingEx {
public static void main(String[] args) {
List<Person> persons = createList();
persons.sort(Comparator.comparing(Person::getAge).reversed());
System.out.println(persons);
}
private static List<Person> createList() {
List<Person> persons = new ArrayList<>();
persons.add(new Person(17, "Jane"));
persons.add(new Person(32, "Peter"));
persons.add(new Person(47, "Patrick"));
persons.add(new Person(22, "Mary"));
persons.add(new Person(39, "Robert"));
persons.add(new Person(54, "Greg"));
return persons;
}
}
我们有一个自定义Person
类的ArrayList
。 我们按照年龄的相反顺序对其进行排序。
persons.sort(Comparator.comparing(Person::getAge).reversed());
此行按年龄(从最大到最小)对人员进行分类。
[Age: 54 Name: Greg, Age: 47 Name: Patrick, Age: 39 Name: Robert, Age: 32 Name: Peter,
Age: 22 Name: Mary, Age: 17 Name: Jane]
这是输出。
使用 Java8 流对ArrayList
进行排序
在第二个示例中,我们使用 Java 流对ArrayList
进行排序。 流 API 是一种更强大的排序方式。
com/zetcode/ArrayListSortingEx2.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class Country {
private String name;
private int population;
public Country(String name, int population) {
this.name = name;
this.population = population;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public String toString() {
return "Country{" + "name=" + name
+ ", population=" + population + '}';
}
}
public class ArrayListSortingEx2 {
public static void main(String[] args) {
List<Country> countries = createList();
List<Country> sorted_countries = countries.stream()
.sorted((e1, e2) -> Integer.compare(e1.getPopulation(),
e2.getPopulation())).collect(Collectors.toList());
System.out.println(sorted_countries);
}
private static List<Country> createList() {
List<Country> countries = new ArrayList<>();
countries.add(new Country("Slovakia", 5424000));
countries.add(new Country("Hungary", 9845000));
countries.add(new Country("Poland", 38485000));
countries.add(new Country("Germany", 81084000));
countries.add(new Country("Latvia", 1978000));
return countries;
}
}
在此示例中,我们有一个国家/地区列表。 每个国家都有名字和人口。 这些国家是按人口排序的。
List<Country> sorted_countries = countries.stream()
.sorted((e1, e2) -> Integer.compare(e1.getPopulation(),
e2.getPopulation())).collect(Collectors.toList());
使用stream()
方法,我们从列表创建流。 sorted()
方法根据提供的比较器对元素进行排序。 使用Integer.compare()
,我们比较了国家/地区的人口。 使用collect()
,我们将信息流转换为国家列表。
[Country{name=Latvia, population=1978000}, Country{name=Slovakia, population=5424000},
Country{name=Hungary, population=9845000}, Country{name=Poland, population=38485000},
Country{name=Germany, population=81084000}]
这是输出。 这些国家按人口升序排序。
使用ArrayList
和简单的 Java 数组
下面的示例使用带有简单 Java 数组的ArrayList
。
com/zetcode/ListToArray.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
public class ListToArray {
public static void main(String[] args) {
List<String> planets = Arrays.asList("Mercury", "Venus", "Earth",
"Mars", "Jupiter", "Saturn", "Uranus", "Neptune");
System.out.println(planets);
String[] planets2 = planets.toArray(new String[0]);
System.out.println(Arrays.toString(planets2));
}
}
ArrayList
转换为数组,反之亦然。
List<String> planets = Arrays.asList("Mercury", "Venus", "Earth",
"Mars", "Jupiter", "Saturn", "Uranus", "Neptune");
使用Arrays.asList()
方法,我们创建了一个由指定数组支持的固定大小的列表。
String[] planets2 = planets.toArray(new String[0]);
ArrayList
的toArray()
用于将列表转换为数组。
流到列表的转换
可以使用收集器将 Java 流转换为列表。
com/zetcode/ToList.java
package com.zetcode;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ToList {
public static void main(String[] args) {
var words = Stream.of("forest", "eagle", "river", "cloud", "sky");
List<String> words2 = words.collect(Collectors.toList());
System.out.println(words2.getClass());
}
}
我们有一串串的字符串。 我们使用Collectors.toList()
将流转换为列表。
class java.util.ArrayList
这是输出。
在本教程中,我们使用了 Java ArrayList
容器。
您可能也对以下相关教程感兴趣: Java HashMap
教程, Java HashSet
教程, Java 教程, Google Guava 简介 ,在 Java 中过滤列表,或在 Java 中读取网页。
列出所有 Java 教程。
用 Java 读写 ICO 图像
原文:http://zetcode.com/articles/javaico/
在本文中,我们展示了如何在 Java 中读取和写入 ICO 图像。
ICO 是在 Microsoft Windows 上的图标中使用的图像文件格式。 ICO 文件包含一个或多个具有多种大小和颜色深度的小图像,因此可以适当缩放它们。 ICO 文件也经常用于网络上的收藏夹图标。
要使用 Java 读写 ICO 文件,我们使用 image4j 图片库。 可以从 image4j.sourceforge.net 下载用于 image4j 的 JAR。
将 PNG 转换为 ICO
在以下示例中,我们将 PNG 图像转换为 ICO 图像。
ConvertToIcoEx.java
package com.zetcode;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import net.sf.image4j.codec.ico.ICOEncoder;
public class ConvertToIcoEx {
public static void main(String[] args) throws IOException {
BufferedImage bi = ImageIO.read(new File("laptop.png"));
ICOEncoder.write(bi, new File("laptop.ico"));
}
}
我们使用ImageIO.read()
方法将 PNG 文件读入BufferedImage
。 BufferedImage
是存储在内存中的像素矩形。 它是 Swing 中最重要的图像类型之一。
ICOEncoder.write(bi, new File("laptop.ico"));
ICOEncoder.write()
将 PNG 转换为 ICO 文件。
将 ICO 转换为 PNG
在第二个示例中,我们将 ICO 图像转换为 PNG 图像。
ConvertIcoToPngEx.java
package com.zetcode;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import net.sf.image4j.codec.ico.ICODecoder;
public class ConvertIcoToPngEx {
public static void main(String[] args) throws IOException {
List<BufferedImage> images = ICODecoder.read(new File("favicon.ico"));
ImageIO.write(images.get(0), "png", new File("favicon.png"));
}
}
我们使用ICODecoder.read()
方法将 ICO 文件读入BufferedImage
。 通过ImageIO.write()
方法将BufferedImage
写入 PNG 文件。
下载 ICO 文件
在下一个示例中,我们从网站下载 ICO 文件,将其转换为ImageIcon
,并在JLabel
组件中显示。
DownloadIcoEx.java
package com.zetcode;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import net.sf.image4j.codec.ico.ICODecoder;
/**
* The example downloads a favicon and displays it in a JLabel.
*
* @author Jan Bodnar
* @website zetcode.com
*/
public class DownloadIcoEx extends JFrame {
public DownloadIcoEx() {
initUI();
}
private void initUI() {
List<BufferedImage> images = readImage();
ImageIcon icon = new ImageIcon(images.get(0));
JLabel lbl = new JLabel(icon);
createLayout(lbl);
setTitle("Ico image");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private List<BufferedImage> readImage() {
List<BufferedImage> images = null;
try {
String path = "http://stackoverflow.com/favicon.ico";
InputStream istr = new URL(path).openStream();
images = ICODecoder.read(istr);
} catch (MalformedURLException ex) {
Logger.getLogger(DownloadIcoEx.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(DownloadIcoEx.class.getName()).log(Level.SEVERE, null, ex);
}
return images;
}
private void createLayout(JComponent... arg) {
Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(150)
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addGap(100)
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
DownloadIcoEx ex = new DownloadIcoEx();
ex.setVisible(true);
});
}
}
该示例从 StackOverflow 网站下载了一个图标。
String path = "http://stackoverflow.com/favicon.ico";
InputStream istr = new URL(path).openStream();
我们从 URL 创建一个InputStream
。
images = ICODecoder.read(istr);
ICODecoder.read()
从InputStream
读取到BufferedImage
ImageIcon icon = new ImageIcon(images.get(0));
从BufferedImage
创建一个ImageIcon
。
JLabel lbl = new JLabel(icon);
将ImageIcon
放入JLabel
。
图:Favicon
在本文中,我们已使用 image4j 库读取和写入 ICO 图像。
您可能也对以下相关教程感兴趣: Java 教程, Java Swing 教程或 Android 教程。
Java int
到String
的转换
原文:http://zetcode.com/java/inttostring/
Java int
到String
教程展示了如何将整数转换为字符串。 有几种方法可以在 Java 中执行从int
到String
的转换。 我们可以使用字符串连接,字符串格式化,字符串构建以及内置的转换方法。
整数到字符串的转换
整数到字符串的转换是类型转换或类型转换,其中整数数据类型的实体更改为字符串一。
在本教程的示例中,我们构建了一个包含整数的字符串消息。
使用String.format()
将int
转换为String
String.format()
使用指定的格式字符串和参数返回格式化的字符串。
JavaIntToString.java
package com.zetcode;
public class JavaIntToString {
public static void main(String[] args) {
int numOfApples = 16;
String msg = String.format("There are %s apples", numOfApples);
System.out.println(msg);
}
}
该示例使用String.format()
进行从int
到String
的转换。
使用字符串连接将int
转换为String
当我们在int
和String
参数上使用+
运算符时,Java 编译器在内部执行类型转换。 请注意,许多 Java 程序员都不喜欢这种转换。
JavaIntToString2.java
package com.zetcode;
public class JavaIntToString2 {
public static void main(String[] args) {
int numOfApples = 16;
String msg = "There are " + numOfApples + " apples";
System.out.println(msg);
}
}
该示例使用字符串连接将 int 转换为 String。 在内部,Java 编译器使用StringBuilder
进行转换。
使用Integer.toString()
将int
转换为String
Integer.toString()
将其参数转换为带符号的十进制表示形式,并以字符串形式返回。
JavaIntToString3.java
package com.zetcode;
public class JavaIntToString3 {
public static void main(String[] args) {
int numOfApples = 16;
String msg = "There are " + Integer.toString(numOfApples) + " apples";
System.out.println(msg);
}
}
该示例使用Integer.toString()
进行从int
到String
的转换。
使用String.valueOf()
将int
转换为String
String.valueOf()
返回整数参数的字符串表示形式。 使用String.valueOf()
时,Java 编译器内部调用Integer.toString()
。
String.valueOf()
被许多人认为是最易读的方法。
JavaIntToString4.java
package com.zetcode;
public class JavaIntToString4 {
public static void main(String[] args) {
int nOfApples = 16;
String msg = "There are " + String.valueOf(nOfApples) + " apples";
System.out.println(msg);
}
}
该示例使用String.valueOf()
进行从int
到String
的转换。
使用StringBuilder
将int
转换为String
StringBuilder
表示可变的字符串。 我们可以使用StringBuilder
构造字符串。 我们也可以将整数附加到生成器。
JavaIntToString5.java
package com.zetcode;
public class JavaIntToString5 {
public static void main(String[] args) {
int numOfApples = 16;
StringBuilder msg = new StringBuilder();
msg.append("There are ").append(numOfApples).append(" apples");
System.out.println(msg);
}
}
该代码示例使用StringBuilder
进行从int
到String
的转换。
Java int
到String
的示例
以下示例使用Scanner
从用户读取一个整数。 然后,将一条字符串消息打印到控制台,其中包含用户的输入。
JavaIntToStringEx.java
package com.zetcode;
import java.util.Scanner;
public class JavaIntToStringEx {
public static void main(String[] args) {
System.out.print("Enter number of apples: ");
try (Scanner scan = new Scanner(System.in)) {
int numOfApples = scan.nextInt();
String msg = String.format("There are %d apples", numOfApples);
System.out.println(msg);
}
}
}
我们使用String.format()
将int
转换为String
。
try (Scanner scan = new Scanner(System.in)) {
Scanner
是一个简单的文本扫描程序,可以使用正则表达式解析原始类型和字符串。 我们使用Scanner
来读取用户的输入。
int numOfApples = scan.nextInt();
nextInt()
方法将输入的下一个标记扫描为int
。
String msg = String.format("There are %d apples", numOfApples);
使用String.format()
创建一条消息。 它以用户输入作为第二个参数。
在本教程中,我们展示了如何在 Java 中将整数转换为字符串。 您可能也对相关教程感兴趣: Java StringBuilder
教程, Java HashSet
教程, Java HashMap
教程, Java static
关键字, Java 中的 HashMap
迭代, Java8 forEach
教程,读取 Java 中的文本文件,用 Java 读取和写入 ICO 图像, Java 教程,用 Java 显示图像。
Java HashSet
教程
原文:http://zetcode.com/java/hashset/
Java HashSet
教程显示了如何使用 Java HashSet
集合。
Java HashSet
HashSet
是一个不包含重复元素的集合。 此类为基本操作(添加,删除,包含和调整大小)提供恒定的时间性能。 HashSet
不提供元素的排序。 HashSet
没有用于检索元素的get()
方法。
HashSet
实现Set
接口。 Set
是一个没有重复的集合。 该接口对数学集合抽象进行建模。
Java HashSet
构造器
HashSet()
- 构造一个默认的空集。HashSet(int initialCapacity)
- 使用给定的初始容量构造一个新的空集。 当元素添加到HashSet
时,容量会自动增长。HashSet(int initialCapacity, float loadFactor)
- 使用给定的初始容量和负载因子构造一个新的空集。HashSet(Collection<? extends E> c)
- 构造一个新集合,其中包含指定集合的元素。
E
是元素的类型。
Java HashSet
方法
下表提供了几种HashSet
方法。
修饰符和类型 | 方法 | 描述 |
---|---|---|
void |
clear() |
从集合中删除所有元素。 |
Object |
clone() |
返回HashSet 实例的浅表副本:元素本身未克隆。 |
boolean |
contains(Object o) |
集合为空,则返回true 。 |
boolean |
add(E e) |
如果指定的元素尚不存在,则将其添加到该集合中。 |
boolean |
remove(Object o) |
从该集合中删除指定的元素(如果存在)。 |
boolean |
removeAll(Collection<?> c) |
从该集合中删除指定集合中包含的所有元素。 |
Iterator<E> |
iterator() |
返回此集合中元素的迭代器。 |
int |
size() |
返回此集合中的元素数。 |
在本教程中,我们将使用其中的几种方法。
Java HashSet
创建
用new
关键字创建HashSet
。
Set<String> brands = new HashSet<>();
尖括号之间的元素类型。 由于类型推断,因此不必在声明的右侧提供类型。
Java HashSet
添加元素
add()
方法用于将元素添加到集合中。
brands.add("Pepsi");
参数是要添加到集合中的元素。
Java HashSet
确定容量
size()
方法返回集合中的元素数。
int nOfElements = brands.size();
Java HashSet
示例 I
下面的示例创建一个HashSet
,确定其大小,并将所有元素打印到控制台。
HashSetSize.java
package com.zetcode;
import java.util.HashSet;
import java.util.Set;
public class HashSetSize {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("IBM");
brands.add("IBM");
int nOfElements = brands.size();
System.out.format("The set contains %d elements%n", nOfElements);
System.out.println(brands);
}
}
在代码示例中,我们创建了一个品牌HashSet
。 每个品牌都必须是唯一的。 例如,不能有两个 IBM 公司注册。
brands.add("IBM");
brands.add("IBM");
甚至以为我们尝试两次添加一个品牌,但一组仅包含一个 IBM 品牌。
int nOfElements = brands.size();
我们确定brands
集的大小。
System.out.println(brands);
所有元素都将打印到控制台。
The set contains 4 elements
[Nike, Volvo, IBM, Wilson]
这是示例的输出。
Java HashSet isEmpty()
isEmpty()
方法检查集合中是否包含任何元素。
brands.isEmpty();
参数是要从此集中删除的对象(如果存在)。
Java HashSet
删除元素
可以使用remove()
和removeAll()
方法删除HashSet
中的元素。
brands.remove("Pepsi");
remove()
方法从集中删除指定的元素(如果存在)。
brands.removeAll(collection);
使用removeAll()
,可以从HashSet
中删除参数集合中包含的所有元素。
Java HashSet
示例 II
在下面的示例中,我们介绍add()
,remove()
,removeAll()
和isEmpty()
方法。
HashSetRemove.java
package com.zetcode;
import java.util.HashSet;
import java.util.Set;
public class HashSetRemove {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("Kia");
brands.add("Lenovo");
Set<String> brands2 = new HashSet<>();
brands2.add("Wilson");
brands2.add("Nike");
brands2.add("Volvo");
System.out.println(brands);
brands.remove("Kia");
brands.remove("Lenovo");
System.out.println(brands);
brands.removeAll(brands2);
System.out.println(brands);
if (brands.isEmpty()) {
System.out.println("The brands set is empty");
}
}
}
该示例构建品牌的HashSet
并从中删除元素。
System.out.println(brands);
初始HashSet
被打印到控制台。
brands.remove("Kia");
brands.remove("Lenovo");
System.out.println(brands);
我们用remove()
删除两个元素,并将brands
的内容打印到控制台。
brands.removeAll(brands2);
System.out.println(brands);
最后,我们从第一组中删除第二组中包含的所有元素。
if (brands.isEmpty()) {
System.out.println("The brands set is empty");
}
如果brands
设置为空,我们将向终端打印一条消息。
[Nike, Lenovo, Kia, Volvo, Wilson]
[Nike, Volvo, Wilson]
[]
The brands set is empty
This is the output of the example.
Java HashSet clear()
clear()
方法从集合中删除所有元素。
brands.clear();
该方法没有参数。
Java HashSet contains()
如果集合包含指定的元素,则contains()
方法返回true
。
brands.contains("Volvo");
参数是要测试其是否存在于该集合中的元素。
Java HashSet
示例 III
在下面的示例中,我们使用add()
,contains()
,clear()
和isEmpty()
方法。
HashSetContains.java
package com.zetcode;
import java.util.HashSet;
import java.util.Set;
public class HashSetContains {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("Kia");
brands.add("Lenovo");
if (brands.contains("Wilson")) {
System.out.println("The set contains the Wilson element");
} else {
System.out.println("The set does not contain the Wilson element");
}
if (brands.contains("Apple")) {
System.out.println("The set contains the Apple element");
} else {
System.out.println("The set does not contain the Apple element");
}
brands.clear();
if (brands.isEmpty()) {
System.out.println("The set does not contain any elements.");
}
}
}
在示例中,我们检查集合中是否存在两个元素。
if (brands.contains("Wilson")) {
System.out.println("The set contains the Wilson element");
} else {
System.out.println("The set does not contain the Wilson element");
}
我们检查集合中是否存在"Wilson"
品牌,并相应地打印一条消息。
The set contains the Wilson element
The set does not contain the Apple element
The set does not contain any elements.
This is the output of the example.
Java HashSet
迭代与forEach()
我们使用 Java8 forEach()
方法来迭代HashSet
的元素。 forEach()
方法对集合中的每个元素执行给定的操作,直到所有元素都已处理或该操作引发异常。
HashSetForEach.java
package com.zetcode;
import java.util.HashSet;
import java.util.Set;
public class HashSetForEach {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("Kia");
brands.add("Lenovo");
brands.forEach(e -> System.out.println(e));
}
}
使用forEach()
方法,我们遍历该集合并将其元素打印到控制台。
使用迭代器的 Java HashSet
迭代
迭代器是用于迭代集合的对象。 使用iterator()
检索迭代器。
HashSetForEach.java
package com.zetcode;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetIterator {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("Kia");
brands.add("Lenovo");
Iterator<String> it = brands.iterator();
while (it.hasNext()) {
String element = it.next();
System.out.println(element);
}
}
}
该代码示例遍历HashSet
的所有元素,并将它们打印到控制台。
Java 使用增强的for
循环迭代HashSet
Java 5 中引入的增强的for
循环可用于对HashSet
进行迭代。
HashSetEnhancedFor.java
package com.zetcode;
import java.util.HashSet;
import java.util.Set;
public class HashSetEnhancedFor {
public static void main(String[] args) {
Set<String> brands = new HashSet<>();
brands.add("Wilson");
brands.add("Nike");
brands.add("Volvo");
brands.add("Kia");
brands.add("Lenovo");
for (String brand: brands) {
System.out.println(brand);
}
}
}
在该示例中,我们迭代具有增强的for
循环的HashSet
。
for (String brand: brands) {
System.out.println(brand);
}
在每个for
循环中,将一个新元素分配给brand
变量。
在本教程中,我们介绍了 Java HashSet
集合。 您可能也对相关教程感兴趣:Java HashMap
教程,Java ArrayList
教程,Java static
关键字,Java 中的HashMap
迭代 ,Java8 forEach
教程,用 Java 读取文本文件,用 Java 读写 ICO 图像,Java 教程和用 Java 显示图像。
Java 字符串
原文:http://zetcode.com/lang/java/strings/
在 Java 教程的这一部分中,我们将更详细地处理字符串数据。
字符串是计算机语言中非常重要的数据类型。 这就是为什么我们将一整章专门讨论 Java 中的字符串的原因。
Java 字符串定义
在 Java 中,字符串是 Unicode 字符序列。 字符串是对象。 有两个用于处理字符串的基本类:
String
StringBuilder
String
是不可变的字符序列。 StringBuilder
是可变的字符序列。 (还有一个StringBuffer
类,可以由多个线程使用。如果不处理线程,则可以使用StringBuilder
。)
字符串字面值源代码中用双引号引起来的一系列字符。 例如,"Java"
是字符串字面值。 每当 Java 编译器在代码中遇到字符串字面值时,它都会使用其值创建一个String
对象。
String lang = "Java"; // same as String lang = new String("Java");
字符串字面值被许多编程语言使用。 这是一个既定的约定,还可以节省键入内容。
Java 初始化字符串
有多种创建字符串的方法,它们都是不可变的和可变的。 我们将展示其中的一些。
com/zetcode/StringInit.java
package com.zetcode;
public class StringInit {
public static void main(String[] args) {
char[] cdb = {'M', 'y', 'S', 'Q', 'L'};
String lang = "Java";
String ide = new String("NetBeans");
String db = new String(cdb);
System.out.println(lang);
System.out.println(ide);
System.out.println(db);
StringBuilder sb1 = new StringBuilder(lang);
StringBuilder sb2 = new StringBuilder();
sb2.append("Fields");
sb2.append(" of ");
sb2.append("glory");
System.out.println(sb1);
System.out.println(sb2);
}
}
该示例显示了创建String
和StringBuilder
对象的几种方法。
String lang = "Java";
最常见的方法是根据字符串字面值创建字符串对象。
String ide = new String("NetBeans");
在这一行中,我们使用构建对象的常用方法创建一个字符串,即使用new
关键字。
String db = new String(cdb);
在这里,我们从字符数组创建一个字符串对象。
StringBuilder sb1 = new StringBuilder(lang);
从String
创建一个StringBuilder
对象。
StringBuilder sb2 = new StringBuilder();
sb2.append("Fields");
sb2.append(" of ");
sb2.append("glory");
我们创建一个空的StringBuilder
对象。 我们将三个字符串附加到对象中。
$ java StringInit.java
Java
NetBeans
MySQL
Java
Fields of glory
运行示例可得出此结果。
Java 字符串是对象
字符串是对象; 它们不是原始数据类型。 字符串是String
或StringBuilder
类的实例。 由于它们是对象,因此有多种方法可用于完成各种工作。
com/zetcode/StringObjects.java
package com.zetcode;
public class StringObjects {
public static void main(String[] args) {
String lang = "Java";
String bclass = lang.getClass().toString();
System.out.println(bclass);
String sup = lang.getClass().getSuperclass().toString();
System.out.println(sup);
if (lang.isEmpty()) {
System.out.println("The string is empty");
} else {
System.out.println("The string is not empty");
}
int l = lang.length();
System.out.println("The string has " + l + " characters");
}
}
在此程序中,我们演示了字符串是对象。 对象必须具有一个类名,一个父类,并且还必须具有一些可以调用的方法。
String lang = "Java";
创建String
类型的对象。
String bclass = lang.getClass().toString();
我们确定lang
变量所引用的对象的类名称。
String sup = lang.getClass().getSuperclass().toString();
接收到我们对象的父类。 所有对象都有至少一个父对象-Object
。
if (lang.isEmpty()) {
System.out.println("The string is empty");
} else {
System.out.println("The string is not empty");
}
对象具有各种方法。 有用的字符串方法之一是isEmpty()
方法,它确定字符串是否为空。
int l = lang.length();
length()
方法返回字符串的大小。
$ java StringObjects.java
class java.lang.String
class java.lang.Object
The string is not empty
The string has 4 characters
我们的字符串对象是String
类的实例。 它具有Object
父类。 该对象不为空,并且包含四个字符。
Java 可变&不可变字符串
String
是不可变字符序列,而StringBuilder
是可变字符序列。 下一个示例将显示差异。
com/zetcode/MutableImmutable.java
package com.zetcode;
public class MutableImmutable {
public static void main(String[] args) {
String name = "Jane";
String name2 = name.replace('J', 'K');
String name3 = name2.replace('n', 't');
System.out.println(name);
System.out.println(name3);
StringBuilder sb = new StringBuilder("Jane");
System.out.println(sb);
sb.setCharAt(0, 'K');
sb.setCharAt(2, 't');
System.out.println(sb);
}
}
这两个对象都有替换字符串中字符的方法。
String name = "Jane";
String name2 = name.replace('J', 'K');
String name3 = name2.replace('n', 't');
在String
上调用replace()
方法将导致返回新的修改后的字符串。 原始字符串不变。
sb.setCharAt(0, 'K');
sb.setCharAt(2, 't');
StringBuilder
的setCharAt()
方法将用新字符替换给定索引处的字符。 原始字符串被修改。
$ java MutableImmutable.java
Jane
Kate
Jane
Kate
这是com.zetcode.MutableImmutable
示例的输出。
Java 连接字符串
可以使用+运算符或concat()
方法添加不可变的字符串。 它们将形成一个新字符串,该字符串是所有连接字符串的链。 可变字符串具有append()
方法,该方法可以从任意数量的其他字符串中构建一个字符串。
com/zetcode/ConcatenateStrings.java
package com.zetcode;
public class ConcatenateStrings {
public static void main(String[] args) {
System.out.println("Return" + " of " + "the king.");
System.out.println("Return".concat(" of ").concat("the king."));
StringBuilder sb = new StringBuilder();
sb.append("Return");
sb.append(" of ");
sb.append("the king.");
System.out.println(sb);
}
}
该示例通过添加字符串来创建三个句子。
System.out.println("Return" + " of " + "the king.");
通过使用+运算符形成一个新的字符串。
System.out.println("Return".concat(" of ").concat("the king."));
concat()
方法返回一个字符串,该字符串表示此对象的字符及其后的字符串参数的字符的连接。
StringBuilder sb = new StringBuilder();
sb.append("Return");
sb.append(" of ");
sb.append("the king.");
通过三次调用append()
方法来创建StringBuilder
类型的可变对象。
$ java ConcatenateStrings.java
Return of the king.
Return of the king.
Return of the king.
这是示例输出。
Java 字符串的引号
在某些情况下,例如使用直接语音,必须对内引号进行转义。
com/zetcode/Quotes.java
package com.zetcode;
public class Quotes {
public static void main(String[] args) {
System.out.println("There are may stars");
System.out.println("He said: \"Which one are you looking at?\"");
}
}
我们使用\
字符转义其他引号。
$ java Quotes.java
There are may stars
He said: "Which one are you looking at?"
在这里,我们看到com.zetcode.Quotes
程序的输出。
Java 多行字符串
Java 13 引入了文本块,该文本块允许定义多行字符串。 要创建多行字符串,我们使用三引号。
com/zetcode/MultilineStrings.java
package com.zetcode;
public class MultilineString {
static String lyrics = """
I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good""";
public static void main(String[] args) {
System.out.println(lyrics);
}
}
我们有一条跨越四行的空想。
$ java MultilineString.java
I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good
我们看到示例的输出。
在 Java 的早期版本中,我们需要执行连接操作并使用\n
字符。
com/zetcode/MultilineString2.java
package com.zetcode;
public class MultilineString2 {
static String lyrics = "I cheated myself\n" +
"like I knew I would\n" +
"I told ya, I was trouble\n" +
"you know that I'm no good";
public static void main(String[] args) {
System.out.println(lyrics);
}
}
这四个字符串用+
运算符连接。
Java 字符串元素
字符串是字符序列。 字符是字符串的基本元素。 以下两个示例显示了一些处理字符串字符的方法。
com/zetcode/StringElements.java
package com.zetcode;
public class StringElements {
public static void main(String[] args) {
char[] crs = {'Z', 'e', 't', 'C', 'o', 'd', 'e' };
String s = new String(crs);
char c1 = s.charAt(0);
char c2 = s.charAt(s.length()-1);
System.out.println(c1);
System.out.println(c2);
int i1 = s.indexOf('e');
int i2 = s.lastIndexOf('e');
System.out.println("The first index of character e is " + i1);
System.out.println("The last index of character e is " + i2);
System.out.println(s.contains("t"));
System.out.println(s.contains("f"));
char[] elements = s.toCharArray();
for (char el : elements) {
System.out.println(el);
}
}
}
在第一个示例中,我们将使用不可变的字符串。
char[] crs = {'Z', 'e', 't', 'C', 'o', 'd', 'e' };
String s = new String(crs);
由字符数组构成一个新的不可变字符串。
char c1 = s.charAt(0);
char c2 = s.charAt(s.length()-1);
使用charAt()
方法,我们获得字符串的第一个和最后一个char
值。
int i1 = s.indexOf('e');
int i2 = s.lastIndexOf('e');
使用indexOf()
和lastIndexOf()
方法,我们得到字符'e'的第一个和最后一个出现。
System.out.println(s.contains("t"));
使用contains()
方法,我们检查字符串是否包含t
字符。 该方法返回一个布尔值。
char[] elements = s.toCharArray();
for (char el : elements) {
System.out.println(el);
}
toCharArray()
方法从字符串创建一个字符数组。 我们遍历数组并打印每个字符。
$ java StringElements.java
Z
e
The first index of character e is 1
The last index of character e is 6
true
false
Z
e
t
C
o
d
e
This is the example output.
在第二个示例中,我们将处理StringBuilder
类的元素。
com/zetcode/StringBuilderElements.java
package com.zetcode;
public class StringBuilderElements {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Misty mountains");
System.out.println(sb);
sb.deleteCharAt(sb.length()-1);
System.out.println(sb);
sb.append('s');
System.out.println(sb);
sb.insert(0, 'T');
sb.insert(1, 'h');
sb.insert(2, 'e');
sb.insert(3, ' ');
System.out.println(sb);
sb.setCharAt(4, 'm');
System.out.println(sb);
}
}
形成可变的字符串。 我们通过删除,附加,插入和替换字符来修改字符串的内容。
sb.deleteCharAt(sb.length()-1);
这行删除最后一个字符。
sb.append('s');
删除的字符将附加回字符串。
sb.insert(0, 'T');
sb.insert(1, 'h');
sb.insert(2, 'e');
sb.insert(3, ' ');
我们在字符串的开头插入四个字符。
sb.setCharAt(4, 'm');
最后,我们在索引 4 处替换一个字符。
$ java StringBuilderElements.java
Misty mountains
Misty mountain
Misty mountains
The Misty mountains
The misty mountains
从输出中,我们可以看到可变字符串是如何变化的。
回文示例
回文是一个单词,数字,短语或其他字符序列,它们的向前和向后读取相同,例如女士或赛车。 有很多方法可以检查字符串是否是回文。 以下示例是可能的解决方案之一。
com/zetcode/Palindrome.java
package com.zetcode;
// A palindrome is a word, number, phrase, or other sequence of characters
// which reads the same backward as forward, such as madam or racecar
public class Palindrome3 {
public static void main(String[] args) {
System.out.println(isPalindrome("radar"));
System.out.println(isPalindrome("kayak"));
System.out.println(isPalindrome("forest"));
}
private static boolean isPalindrome(String original) {
char[] data = original.toCharArray();
int i = 0;
int j = data.length - 1;
while (j > i) {
if (data[i] != data[j]) {
return false;
}
++i;
--j;
}
return true;
}
}
我们已经实现了isPalindrome()
方法。
private static boolean isPalindrome(String original) {
char[] data = original.toCharArray();
...
我们将字符串转换为字符数组。
int i = 0;
int j = data.length - 1;
while (j > i) {
if (data[i] != data[j]) {
return false;
}
++i;
--j;
}
return true;
我们遍历数组,并将左侧字符与右侧对应字符进行比较。 如果全部匹配,则返回true
,否则返回false
。
$ java Palindrome.java
true
true
false
这是输出。
Java 子字符串
substring()
方法返回字符串的一部分。 起始索引是包含的,结束索引是排斥的。 起始索引从零开始。
com/zetcode/Substrings.java
package com.zetcode;
public class Substrings {
public static void main(String[] args) {
String str = "bookcase";
System.out.println(str.substring(0, 4));
System.out.println(str.substring(4, str.length()));
}
}
该示例使用substring()
方法创建两个子字符串。
System.out.println(str.substring(0, 4));
在这里,我们得到"book"
子字符串。 零是指字符串的第一个字符。
System.out.println(str.substring(4, str.length()));
在此打印"case"
子字符串。
$ java Substrings.java
book
case
这是输出。
Java 分割字符串
split()
方法将字符串分割成几部分; 它使用定界正则表达式作为参数。
com/zetcode/Splitting.java
package com.zetcode;
public class Splitting {
public static void main(String[] args) {
String s = "Today is a beautiful day.";
String[] words = s.split(" ");
for (String word : words) {
System.out.println(word);
}
}
}
该示例将句子拆分为单词。
String s = "Today is a beautiful day.";
这是一个句子。 单词之间用空格隔开。
String[] words = s.split(" ");
使用split()
方法,我们将句子切成单词。 空格字符用作分隔符。 该方法返回一个字符串数组。
for (String word : words) {
System.out.println(word);
}
我们遍历数组并打印其内容。
$ java Splitting.java
Today
is
a
beautiful
day.
这是输出。
Java 删除字符串字符
当我们将字符串拆分为单词时,某些单词的开头或结尾字符为逗号或点号。 在下一个示例中,我们显示如何删除此类字符。
com/zetcode/RemovingChars.java
package com.zetcode;
public class RemovingChars {
public static void main(String[] args) {
String str = "Did you go there? We did, but we had a \"great\" service there.";
String[] parts = str.split(" ");
for (String part: parts) {
String word = removeChars(part);
System.out.println(word);
}
}
private static String removeChars(String part) {
String word = part;
if (part.endsWith(".") || part.endsWith("?") || part.endsWith(",")) {
word = part.substring(0, part.length()-1);
}
if (part.startsWith("\"") && part.endsWith("\"")) {
word = part.substring(1, part.length()-1);
}
return word;
}
}
该示例将字符串拆分为单词,并删除潜在的逗号,点,问号或双引号。
String str = "Did you go there? We did, but we had a \"great\" service there.";
在此字符串中,我们有一个问号,逗号,引号和附加在单词上的圆点。
private static String removeChars(String part) {
在此自定义方法内,我们从单词中删除了这些字符。
if (part.endsWith(".") || part.endsWith("?") || part.endsWith(",")) {
word = part.substring(0, part.length()-1);
}
在此if
语句中,我们删除结尾字符。 我们使用endsWith()
方法来标识要删除的字符。 substring()
方法返回不包含字符的字符串的一部分。
if (part.startsWith("\"") && part.endsWith("\"")) {
word = part.substring(1, part.length()-1);
}
同样,我们删除起始字符。 起始字符通过startsWith()
方法检查。
$ java RemovingChars.java
Did
you
go
there
We
did
but
we
had
a
great
service
there
这是示例的输出。 字符已成功删除。
Java 连接字符串
从 Java8 开始,我们有了join()
方法来连接字符串。 请参阅 StringJoiner 教程,以了解有关在 Java 中连接字符串的更多信息。
com/zetcode/Joining.java
package com.zetcode;
public class Joining {
public static void main(String[] args) {
String joined = String.join(" ", "Today", "is", "Sunday");
System.out.println(joined);
}
}
在示例中,我们将三个字符串合并为一个最终字符串。
String joined = String.join(" ", "Today", "is", "Sunday");
join()
方法的第一个参数是定界符,它将分隔最终字符串中的每个字符串。 其余参数是要连接的字符串。
Java 比较字符串
比较字符串有两种基本方法。 equals()
方法比较两个字符串的内容,并返回一个布尔值,指示字符串是否相等。 equalsIgnoreCase()
做相同的事情,除了它忽略大小写。
com/zetcode/ComparingStrings.java
package com.zetcode;
public class ComparingStrings {
public static void main(String[] args) {
String a = "book";
String b = "Book";
System.out.println(a.equals(b));
System.out.println(a.equalsIgnoreCase(b));
}
}
我们使用上述方法比较两个字符串。
String a = "book";
String b = "Book";
我们定义了两个要比较的字符串。
System.out.println(a.equals(b));
equals()
方法返回false
。 两个字符串的第一个字符不同。
System.out.println(a.equalsIgnoreCase(b));
当我们忽略大小写时,字符串是相等的:equalsIgnoreCase()
方法返回true
。
$ java ComparingStrings.java
false
true
这是程序的输出。
如果我们正在将变量与字符串进行比较,则切记字符串应位于比较方法的左侧,这一点很重要。 否则我们可能会得到NullPointerException
。
com/zetcode/ComparingStrings2.java
import java.util.Random;
public class ComparingStrings2 {
public static String readString() {
Random r = new Random();
boolean b = r.nextBoolean();
if (b == true) {
return "ZetCode";
} else {
return null;
}
}
public static void main(String[] args) {
String d = readString();
if ("ZetCode".equals(d)) {
System.out.println("Strings are equal");
} else {
System.out.println("Strings are not equal");
}
}
}
在代码示例中,我们正确地比较了字符串,避免了可能的NullPointerException
。
public static String readString() {
Random r = new Random();
boolean b = r.nextBoolean();
if (b == true) {
return "ZetCode";
} else {
return null;
}
}
readString()
方法模拟方法调用可能导致空值的情况。 例如,如果我们尝试从数据库中读取值,则可能会发生这种情况。
String d = readString();
d
变量可以包含空值。
if ("ZetCode".equals(d)) {
上一行是比较两个字符串的正确方法,其中一个字符串是已知字面值。 如果将d
变量放在左侧,则如果d
变量包含空值,则将导致NullPointerException
。
equals()
方法比较两个字符串的字符。 ==
运算符测试引用是否相等。 所有字符串字面值都将使用 Java 自动插入。 它们被放置在字符串池中。 这是在编译时发生的。 如果两个变量包含两个相等的字符串字面值,则它们实际上引用字符串池中的同一字符串对象。
com/zetcode/ComparingStrings3.java
package com.zetcode;
public class ComparingStrings3 {
public static void main(String[] args) {
boolean a = "ZetCode" == "ZetCode";
boolean b = "ZetCode" == new String("ZetCode");
boolean c = "ZetCode" == "Zet" + "Code";
boolean d = "ZetCode" == new String("ZetCode").intern();
boolean e = "ZetCode" == " ZetCode ".trim();
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(e);
}
}
在此代码示例中,我们将字符串对象与==
运算符进行比较。
boolean a = "ZetCode" == "ZetCode";
这些字符串字面值是内部的。 因此,身份比较运算符返回true
。
boolean b = "ZetCode" == new String("ZetCode");
使用new
运算符创建的字符串不会被保留。 比较运算符导致错误的值。
boolean c = "ZetCode" == "Zet" + "Code";
字符串在编译时连接在一起。 字符串字面值导致相同的对象。 结果是正确的。
boolean d = "ZetCode" == new String("ZetCode").intern();
intern()
对象将右侧的字符串对象放入池中。 因此,d 变量为布尔值 true。
boolean e = "ZetCode" == " ZetCode ".trim();
在运行时调用trim()
方法,生成一个不同的对象。 e
变量具有布尔值false
。
$ java ComparingStrings3.java
true
false
true
true
false
这是示例的输出。
Java 格式化字符串
我们可以同时使用System.out.printf()
和System.out.format()
方法来格式化 Java 中的字符串。 它们的工作原理相同。 这两种方法使用指定的格式字符串和参数将格式字符串写入输出流。 如果参数多于格式说明符,则多余的参数将被忽略。
%[argument_index$][flags][width][.precision]conversion
常规,字符和数字类型的格式说明符具有此语法。
%[argument_index$][flags][width]conversion
这是用于表示日期和时间的类型的语法。
格式说明符以%
字符开头,以 1 或 2 个字符转换结尾,该转换符指定要生成的格式化输出的种类。 可选项目放在方括号之间。
arguments_index
是一个十进制整数,指示参数在参数列表中的位置。 标志是一组修改输出格式的字符。 有效标志集取决于转换。 宽度是一个非负的十进制整数,指示要写入输出的最小字符数。 精度是通常用于限制字符数的非负十进制整数。 具体行为取决于转换。 所需的转换是一个字符,指示应如何格式化参数。
com/zetcode/Conversions.java
package com.zetcode;
public class Conversions {
public static void main(String[] args) {
System.out.format("There are %d %s.%n", 5, "pencils");
System.out.printf("The rock weighs %f kilograms.%n", 5.345);
}
}
在此程序中,我们格式化两个简单的句子。
System.out.format("There are %d %s.%n", 5, "pencils");
在此代码行中,我们有三个格式说明符。 每个说明符均以%
字符开头。 d
说明符格式化整数值。 s
说明符需要字符串值。 %n
输出平台特定的线路终端器; 它不需要参数。
System.out.printf("The rock weighs %f kilograms.%n", 5.345);
f
将浮点值格式化为十进制值。 System.out.printf()
与System.out.format()
的工作相同。
$ java Conversions.java
There are 5 pencils.
The rock weighs 5.345000 kilograms.
This is the output of the program.
com/zetcode/IndexPosition.java
package com.zetcode;
import java.util.Calendar;
public class IndexPosition {
public static void main(String[] args) {
int x = 12;
int y = 32;
int z = 43;
Calendar c = Calendar.getInstance();
System.out.format("There are %d apples, %d oranges and "
+ "%d pears%n", x, y, z);
System.out.format("There are %2$d apples, %3$d oranges and "
+ "%1$d pears%n", x, y, z);
System.out.format("Year: %tY, Month: %<tm, Day: %<td%n", c);
}
}
该示例使用参数索引来引用包含在参数列表中的变量。
System.out.format("There are %d apples, %d oranges and "
+ "%d pears%n", x, y, z);
如果不指定索引,则变量将自动与指定符匹配。 d
说明符将整数值格式化为十进制值。
System.out.format("There are %2$d apples, %3$d oranges and "
+ "%1$d pears%n", x, y, z);
1$
引用x
变量,2$
引用y
变量,3$
引用z
变量。
System.out.format("Year: %tY, Month: %<tm, Day: %<td%n", c);
<
标志使先前格式说明符的参数被重用。 这三个说明符均引用c
变量。 tY
转换字符给出的年份格式至少为四位数字,必要时带有前导零。tm
给出一个月份,格式为两位数字,必要时以前导零,而td
给出月份中的某一天,格式为两位数字,必要时带有前导零。
$ java IndexPosition.java
There are 12 apples, 32 oranges and 43 pears
There are 32 apples, 43 oranges and 12 pears
Year: 2016, Month: 09, Day: 07
This is the output of the program.
标志以特定方式修改格式。 有几个标志。 例如,+
标志要求输出为所有正数包括一个正号。
com/zetcode/Flags.java
package com.zetcode;
public class Flags {
public static void main(String[] args) {
System.out.format("%+d%n", 553);
System.out.format("%010d%n", 553);
System.out.format("%10d%n", 553);
System.out.format("%-10d%n", 553);
System.out.format("%d%n", -553);
System.out.format("%(d%n", -553);
}
}
该示例显示了一些字符串格式说明符的标志。
System.out.format("%010d%n", 553);
0
标志将使输出填充前导零到最小字段宽度。 我们的电话号码有三位数。 最小宽度为 10。因此,输出中有 7 个前导零。
System.out.format("%10d%n", 553);
如果没有0
标志,该数字将右对齐。
System.out.format("%-10d%n", 553);
-
标志将使数字左对齐。
System.out.format("%d%n", -553);
System.out.format("%(d%n", -553);
默认情况下,负数带有减号。 如果我们使用(
标志,则负值将放在圆括号内。 (这用于会计。)
$ java Flags.java
+553
0000000553
553
553
-553
(553)
在这里,我们看到com.zetcode.Flags
示例的输出。
width
字段是要写入输出的最小字符数。 不能与行分隔符一起使用。
com/zetcode/WidthSpecifier.java
package com.zetcode;
public class WidthSpecifier {
public static void main(String[] args) {
System.out.println(1);
System.out.println(16);
System.out.println(1655);
System.out.println(16567);
System.out.println(166701);
System.out.format("%10d%n", 1);
System.out.format("%10d%n", 16);
System.out.format("%10d%n", 1655);
System.out.format("%10d%n", 16567);
System.out.format("%10d%n", 166701);
}
}
首先,我们打印五个数字而不指定字段宽度。 输出的宽度等于要显示的字符数。 在第二种情况下,字段宽度为 10。5 个输出中的每个输出的最小长度为 10 个字符。 数字右对齐。
System.out.format("%10d%n", 1);
数字 10 指出字符串输出必须至少包含十个字符。
$ java WidthSpecifier.java
1
16
1655
16567
166701
1
16
1655
16567
166701
我们可以看到,在第二种情况下,数字是右对齐的。
对于不同的转换,精度字段具有不同的含义。 对于常规参数类型,精度是要写入输出的最大字符数。
com/zetcode/PrecisionSpecifier.java
package com.zetcode;
public class PrecisionSpecifier {
public static void main(String[] args) {
System.out.format("%.3g%n", 0.0000006);
System.out.format("%.3f%n", 54.34263);
System.out.format("%.3s%n", "ZetCode");
}
}
在三个不同的输出上演示了精度说明符。
System.out.format("%.3g%n", 0.0000006);
如果使用g
转换,则精度是四舍五入后得到的幅度中的位数总数。
System.out.format("%.3f%n", 54.34263);
对于浮点值,精度是小数点分隔符后的位数。
System.out.format("%.3s%n", "ZetCode");
对于字符串,它是最大可打印字符数。 七个字符中只有三个字符被打印到控制台。
$ java PrecisionSpecifier.java
6.00e-07
54.343
Zet
This is the example output.
下一个示例将格式化数字数据。
com/zetcode/FormatNumbers.java
package com.zetcode;
public class FormatNumbers {
public static void main(String[] args) {
System.out.format("%d%n", 12263);
System.out.format("%o%n", 12263);
System.out.format("%x%n", 12263);
System.out.format("%e%n", 0.03452342263);
System.out.format("%d%%%n", 45);
}
}
该示例演示了数字的标准格式说明符。
System.out.format("%d%n", 12263);
d
转换说明符会将整数值转换为十进制值。
System.out.format("%o%n", 12263);
o
转换说明符会将数字格式化为八进制。
System.out.format("%x%n", 12263);
使用x
说明符,结果被格式化为十六进制整数。
System.out.format("%e%n", 0.03452342263);
使用e
指示符,以科学计数法打印数字。
System.out.format("%d%%%n", 45);
%%
字符用于打印百分号。
$ java FormatNumbers.java
12263
27747
2fe7
3.452342e-02
45%
该程序以不同的格式打印数字。
最后,我们将格式化日期和时间数据。
com/zetcode/FormatDateTime.java
package com.zetcode;
import java.time.LocalDateTime;
public class FormatDateTime {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.now();
System.out.format("%tF%n", ldt);
System.out.format("%tD%n", ldt);
System.out.format("%tT%n", ldt);
System.out.format("%1$tA, %1$tb %1$tY%n", ldt);
System.out.format("%1$td.%1$tm.%1$tY%n", ldt);
}
}
该示例演示了日期的标准格式说明符。 日期和时间格式字符串的转换部分以t
字符开头。
System.out.format("%tF%n", c);
作为tF
转换的结果,此行以完整的 ISO 8601 格式打印日期。
System.out.format("%1$td.%1$tm.%1$tY%n", c);
使用这些格式说明符,我们以斯洛伐克使用的格式打印日期。 这些部分由点字符分隔,并且日期在月份之前,月份在年份之前。 所有这三种格式说明符均引用c
变量。
$ java FormatDateTime.java
2019-10-02
10/02/19
15:45:02
Wednesday, Oct 2019
02.10.2019
This is the output of the program.
Java 教程的这一部分更详细地介绍了字符串。
{% raw %}
Java HashMap
教程
原文:http://zetcode.com/java/hashmap/
Java HashMap
教程显示了如何使用 Java HashMap
集合。
Java HashMap
HashMap
是一个存储键值对的容器。 每个键与一个值关联。 HashMap
中的键必须唯一。 HashMap
在其他编程语言中称为关联数组或词典。 HashMaps
占用更多内存,因为每个值还有一个键。 删除和插入操作需要固定的时间。 HashMaps
可以存储空值。
HashMaps
不维持秩序。
Map.Entry
表示HashMap
中的键/值对。 HashMap
的entrySet()
返回包含在映射中的映射的Set
视图。 使用keySet()
方法检索一组键。
Java HashMap
层次结构
HashMap
扩展了AbstractMap
并实现了Map
。 Map
提供了包括get()
,put()
,size()
或isEmpty()
的方法签名。
Java HashMap
构造器
HashMap()
-构造一个空的HashMap()
,其默认初始容量(16)和默认负载因子(0.75)。HashMap(int initialCapacity)
-构造一个空的HashMap()
,具有给定的初始容量和默认的负载系数(0.75)。HashMap(int initialCapacity, float loadFactor)
-使用给定的初始容量和负载因子构造一个空的HashMap()
。HashMap(Map<? extends K,? extends V> m)
—构造一个新的HashMap()
,其映射与给定的Map
相同。
K
是映射键的类型,V
是映射值的类型。
Java HashMap
方法
下表提供了几种HashMap
方法。
修饰符和类型 | 方法 | 描述 |
---|---|---|
void |
clear() |
从映射中删除所有映射。 |
Object |
clone() |
返回HashMap 实例的浅表副本:键和值本身不会被克隆。 |
boolean |
containsKey(Object key) |
如果此映射包含指定键的映射,则返回true 。 |
Set<Map.Entry<K, V>> |
entrySet() |
返回此映射中包含的映射的Set 视图。 |
boolean |
isEmpty() |
如果此映射为空,则返回true 。 |
Set<K> |
keySet() |
返回此映射中包含的键的Set 视图。 |
V |
put(K key, V value) |
向映射添加新的映射。 |
V |
remove(Objec key) |
如果存在,则从此映射中删除指定键的映射。 |
V |
get(Object key) |
返回指定键所映射到的值;如果此映射不包含键的映射关系,则返回null 。 |
void |
forEach(BiConsumer<? super K, ? super V> action) |
在此映射中为每个条目执行给定的操作,直到所有条目都已处理或该操作引发异常。 |
V |
replace(K key, V value) |
仅当当前映射到某个值时,才替换指定键的条目。 |
int |
size() |
返回此映射中的键值映射数。 |
Collection<V> |
values() |
返回此映射中包含的值的Collection 视图。 |
在本教程中,我们将使用其中的几种方法。
Java HashMap
创建
用new
关键字创建HashMap
。
Map<String, String> capitals = new HashMap<>();
我们在尖括号之间指定键的类型和值。 由于类型推断,因此不必在声明的右侧提供类型。
Java HashMap put()
put()
方法用于向映射添加新的映射。
capitals.put("svk", "Bratislava");
第一个参数是键,第二个是值。
Java HashMap remove()
remove()
方法用于从映射中删除一对。
capitals.remove("pol");
参数是要从映射中删除其映射的键。
Java HashMap
初始化
从 Java 9 开始,我们有了用于HashMap
初始化的工厂方法。
com/zetcode/HashMapInit.java
package com.zetcode;
import java.util.Map;
import static java.util.Map.entry;
// factory initialization methods since Java 9
public class HashMapInit {
public static void main(String[] args) {
// up to 10 elements:
Map<Integer, String> colours = Map.of(
1, "red",
2, "blue",
3, "brown"
);
System.out.println(colours);
// any number of elements
Map<String, String> countries = Map.ofEntries(
entry("de", "Germany"),
entry("sk", "Slovakia"),
entry("ru", "Russia")
);
System.out.println(countries);
}
}
该示例使用Map.of
和Map.ofEntries
初始化哈希图。 这两个工厂方法返回不可修改的映射。
com/zetcode/HashMapInit2.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
// up to Java8
public class HashMapInit2 {
public static void main(String[] args) {
Map<String, String> countries = new HashMap<>() {{
put("de", "Germany");
put("sk", "Slovakia");
put("ru", "Russia");
}};
System.out.println(countries);
}
}
在此示例中,我们创建了一个可修改的哈希图。 这种初始化方式称为双括号哈希图初始化。
Java HashMap
大小示例
HashMap
的大小由size()
方法确定。
com/zetcode/HashMapSize.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapSize {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
int size = capitals.size();
System.out.printf("The size of the HashMap is %d%n", size);
capitals.remove("pol");
capitals.remove("ita");
size = capitals.size();
System.out.printf("The size of the HashMap is %d%n", size);
}
}
在代码示例中,我们创建HashMap
并使用size()
确定其大小。 然后,我们删除一些对,然后再次确定其大小。 我们将发现结果打印到控制台。
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
使用put()
,我们将新的对添加到HashMap
中。
int size = capitals.size();
在这里,我们得到映射的大小。
capitals.remove("pol");
capitals.remove("ita");
使用remove()
,我们从映射中删除了两对。
The size of the HashMap is 6
The size of the HashMap is 4
这是示例的输出。
Java HashMap get()
要从HashMap
检索值,我们使用get()
方法。 它以键作为参数。
com/zetcode/HashMapRetrieve.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapRetrieve {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
String cap1 = capitals.get("ita");
String cap2 = capitals.get("svk");
System.out.println(cap1);
System.out.println(cap2);
}
}
在示例中,我们从映射中检索两个值。
String cap2 = capitals.get("svk");
在这里,我们得到一个具有"svk"
键的值。
Java HashMap clear()
clear()
方法从HashMap
中删除所有对。
com/zetcode/HashMapClear.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapClear {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
capitals.clear();
if (capitals.isEmpty()) {
System.out.println("The map is empty");
} else {
System.out.println("The map is not empty");
}
}
}
在该示例中,我们删除了所有元素,并将映射的大小打印到控制台。
capitals.clear();
我们用clear()
删除所有对。
if (capitals.isEmpty()) {
System.out.println("The map is empty");
} else {
System.out.println("The map is not empty");
}
使用isEmpty()
方法,我们检查映射是否为空。
Java HashMap containsKey()
如果映射包含指定键的映射,则containsKey()
方法返回true
。
com/zetcode/HashMapContainsKey.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapContainsKey {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
String key1 = "ger";
String key2 = "rus";
if (capitals.containsKey(key1)) {
System.out.printf("HashMap contains %s key%n", key1);
} else {
System.out.printf("HashMap does not contain %s key%n", key1);
}
if (capitals.containsKey(key2)) {
System.out.printf("HashMap contains %s key%n", key2);
} else {
System.out.printf("HashMap does not contain %s key%n", key2);
}
}
}
在示例中,我们检查映射是否包含两个键。
if (capitals.containsKey(key1)) {
System.out.printf("HashMap contains %s key%n", key1);
} else {
System.out.printf("HashMap does not contain %s key%n", key1);
}
该if
语句根据映射是否包含给定键输出消息。
HashMap contains ger key
HashMap does not contain rus key
这是输出。
Java HashMap replace()
有replace()
方法使程序员可以替换条目。
replace(K key, V value)
仅当当前映射到某个值时,此方法才替换指定键的条目。
replace(K key, V oldValue, V newValue)
仅当当前映射到指定值时,此方法才替换指定键的条目。
com/zetcode/HashMapReplace.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapReplace {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("day", "Monday");
capitals.put("country", "Poland");
capitals.put("colour", "blue");
capitals.replace("day", "Sunday");
capitals.replace("country", "Russia", "Great Britain");
capitals.replace("colour", "blue", "green");
capitals.entrySet().forEach(System.out::println);
}
}
在示例中,我们将映射中的对替换为replace()
。
capitals.replace("day", "Sunday");
在这里,我们替换"day"
键的值。
capitals.replace("country", "Russia", "Great Britain");
在这种情况下,由于键当前未设置为"Russia"
,因此不会替换该值。
capitals.replace("colour", "blue", "green");
由于旧值正确,因此将替换该值。
country=Poland
colour=green
day=Sunday
这是输出。
Java HashMap
转换为List
在下一个示例中,我们将HashMap
条目转换为条目列表。
com/zetcode/HashMapConvert.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HashMapConvert {
public static void main(String[] args) {
Map<String, String> colours = Map.of(
"AliceBlue", "#f0f8ff",
"GreenYellow", "#adff2f",
"IndianRed", "#cd5c5c",
"khaki", "#f0e68c"
);
Set<Map.Entry<String, String>> entries = colours.entrySet();
List<Map.Entry<String, String>> mylist = new ArrayList<>(entries);
System.out.println(mylist);
}
}
entrySet()
返回映射的设置视图,该视图随后传递给ArrayList
的构造器。
使用forEach()
迭代HashMap
我们使用 Java8 forEach()
方法来迭代HashMap
的键值对。 forEach()
方法对映射的每个元素执行给定的操作,直到所有元素都已处理或该操作引发异常。
com/zetcode/HashMapForEach.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapForEach {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
capitals.forEach((k, v) -> System.out.format("%s: %s%n", k, v));
}
}
在代码示例中,我们使用 lambda 表达式迭代了HashMap
和forEach()
。
capitals.forEach((k, v) -> System.out.format("%s: %s%n", k, v));
使用forEach()
,我们遍历了映射的所有对。
使用增强的for
循环迭代HashMap
Java 5 中引入的增强的for
循环可用于对HashMap
进行迭代。
com/zetcode/HashMapEnhancedFor.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapEnhancedFor {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
for (Map.Entry<String, String> pair: capitals.entrySet()) {
System.out.format("%s: %s%n", pair.getKey(), pair.getValue());
}
}
}
在该示例中,我们迭代具有增强的for
循环的HashMap
。
for (Map.Entry<String, String> pair: capitals.entrySet()) {
System.out.format("%s: %s%n", pair.getKey(), pair.getValue());
}
在每个for
周期中,都将新的键值对分配给pair
变量。
Java HashMap
迭代键
我们可能只想遍历HashMap
的键。
com/zetcode/HashMapKeys.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapKeys {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Set<String> keys = capitals.keySet();
keys.forEach(System.out::println);
}
}
该示例迭代capitals
映射的键。
Set<String> keys = capitals.keySet();
用keySet()
方法检索HashMap
的键,该方法返回键Set
。 键必须唯一; 因此,我们有一个Set
。 Set
是一个不包含重复元素的集合。
keys.forEach(System.out::println);
我们用forEach()
遍历键集。
Java HashMap
迭代值
我们可能只想对HashMap
的值进行迭代。
com/zetcode/HashMapValues.java
package com.zetcode;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class HashMapValues {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Collection<String> vals = capitals.values();
vals.forEach(System.out::println);
}
}
该示例迭代HashMap
的值。
Collection<String> vals = capitals.values();
HashMap
的值通过values()
方法检索。
vals.forEach(System.out::println);
我们使用forEach()
遍历集合。
HashMap
过滤
可以使用 Java 流 API 的filter()
方法过滤HashMap
。
com/zetcode/HashMapFilter.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class HashMapFilter {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(map -> map.getValue().length() == 6)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filteredCapitals.entrySet().forEach(System.out::println);
}
}
在示例中,我们将映射过滤为仅包含值大小等于 6 的对。
czk=Prague
ger=Berlin
pol=Warsaw
这是输出。
其他语言的 Java HashMap
等效项
Ruby 具有哈希,Perl 具有哈希,PHP 具有数组,Python 具有字典,C# 具有字典,JavaScript 具有映射。
ruby_hash.rb
#!/usr/bin/ruby
stones = { 1 => "garnet", 2 => "topaz",
3 => "opal", 4 => "amethyst"
}
stones.each { |k, v| puts "Key: #{k}, Value: #{v}" }
这是 Ruby 中的哈希。
perl_hash.py
#!/usr/bin/perl
my %stones = ( 1 => "garnet", 2 => "topaz",
3 => "opal", 4 => "amethyst" );
while ( my ($k, $v) = each %stones ) {
print "$k: $v\n";
}
这是一个 Perl 哈希。
php_array.php
<?php
$stones = [
1 => "garnet",
2 => "topaz",
3 => "opal",
4 => "amethyst"
];
foreach ($stones as $key => $value) {
echo "$key: $value\n";
}
?>
这是一个 PHP 数组。
python_dictionary.py
#!/usr/bin/python
stones = { 1 : "garnet",
2 : "topaz",
3 : "opal",
4 : "amethyst" }
for key, value in stones.items():
print("{}: {}".format(key, value))
这是 Python 字典。
csharp_dictionary.cs
using System;
using System.Collections.Generic;
public class DictionaryExample {
static void Main() {
Dictionary<int, string> stones = new Dictionary<int, string> {
{ 1, "garnet" },
{ 2, "topaz" },
{ 3, "opal" },
{ 4, "amethyst" },
};
Console.WriteLine("Keys and values of the dictionary:");
foreach(KeyValuePair<int, string> kvp in stones) {
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
}
}
这是 C# 词典。
javascript_map.js
var stones = new Map();
stones.set(1, 'garnet');
stones.set(2, 'topaz');
stones.set(3, 'opal');
stones.set(4, 'amethyst');
stones.forEach(function(value, key) {
console.log(key + ': ' + value);
});
这是一个 JavaScript 映射。
在本教程中,我们介绍了 Java HashMap
集合。 您可能也对相关教程感兴趣: Java 中的HashMap
迭代, Java ArrayList
教程, Java HashSet
教程, Java static
关键字 和 Java 教程。
列出所有 Java 教程。
{% endraw %}
Java static
关键字
原文:http://zetcode.com/java/statickeyword/
在本教程中,我们将讨论 Java 中的static
关键字。 我们介绍了静态变量,方法,嵌套类,块和导入。
Java static
关键字定义
static
关键字是不可访问的修饰符。 具有static
修饰符的类型不属于类的实例; 它属于此类。 除此之外,static
可用于创建类初始化器,常量,并且无需类限定即可导入静态变量。
static
关键字的用法
static
关键字可以应用于:
- 变量
- 方法
- 块
- 嵌套类
- 导入
Java 静态变量
静态变量也称为类变量。 一个类的所有实例共享一个静态变量的相同副本。 在执行开始时,它们仅初始化一次。 可以通过类名直接访问类变量,而无需创建实例。 static
的一种常见用法是创建一个附加到类的常量值。
静态变量示例
JavaStaticVariable.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
class Being {
public static int count;
}
class Cat extends Being {
public Cat() {
count++;
}
}
class Dog extends Being {
public Dog() {
count++;
}
}
class Donkey extends Being {
public Donkey() {
count++;
}
}
public class JavaStaticVariable {
public static void main(String[] args) {
List<Being> beings = new ArrayList<>();
beings.add(new Cat());
beings.add(new Cat());
beings.add(new Cat());
beings.add(new Dog());
beings.add(new Donkey());
int nOfBeings = Being.count;
System.out.format("There are %d beings %n", nOfBeings);
}
}
在代码示例中,我们跟踪使用静态变量创建的生物。
class Being {
public static int count;
}
定义了一个静态变量。 该变量属于Being
类,并由Being
的所有实例(包括后代)共享。
class Cat extends Being {
public Cat() {
count++;
}
}
Cat
类继承自Being
。 它将增加count
变量。
class Dog extends Being {
public Dog() {
count++;
}
}
Dog
类增加相同的类变量。 因此,Dog
和Cat
指的是同一类变量。
int nOfBeings = Being.count;
我们得到所有被创造的生物的数量。 我们通过类名称,后跟点运算符和变量名称来引用类变量。
Java 静态变量属性
- 静态变量具有默认值。
- 静态变量可以通过静态和非静态方法直接访问。
- 静态变量称为类变量或静态字段。
- 静态变量与类关联,而不与任何对象关联。
Java 静态方法
在没有对象实例的情况下调用静态方法。 要调用静态方法,我们使用类的名称,点运算符和方法的名称。 静态方法只能使用静态变量。 静态方法通常用于表示不会随对象状态变化的数据或计算。 例如,java.lang.Math
包含用于各种计算的静态方法。
我们使用static
关键字声明一个静态方法。 如果不存在static
修饰符,则该方法称为实例方法。
静态方法限制
静态方法只能调用其他静态方法。 它们只能访问静态数据,而不能引用this
和super
。
静态方法示例
JavaStaticMethod.java
package com.zetcode;
class Basic {
static int id = 2321;
public static void showInfo() {
System.out.println("This is Basic class");
System.out.format("The Id is: %d%n", id);
}
}
public class JavaStaticMethod {
public static void main(String[] args) {
Basic.showInfo();
}
}
在我们的代码示例中,我们定义了静态ShowInfo()
方法。
static int id = 2321;
静态方法只能使用静态变量。 静态变量不适用于实例方法。
public static void showInfo() {
System.out.println("This is Basic class");
System.out.format("The Id is: %d%n", id);
}
这是我们的静态ShowInfo()
方法。 它与静态id
成员一起使用。
Basic.showInfo();
要调用静态方法,我们不需要对象实例。 我们通过使用类的名称和点运算符来调用该方法。
Java 静态main()
方法
在 Java 控制台和 GUI 应用中,入口点具有以下特征:
public static void main(String[] args)
通过声明main()
方法static
,运行时引擎可以调用它,而无需创建主类的实例。 由于main()
的主要原因是要引导应用,因此不需要主类的实例。
另外,如果main()
方法不是static
,则将需要其他协定,例如默认构造器或主类的要求不能抽象。 因此,使用static
main()
方法是一种不太复杂的解决方案。
Java 静态块
具有static
修饰符的代码块称为类初始化器。 没有static
修饰符的代码块是实例初始化器。 在加载类时,将按照定义的顺序(从上到下)执行类初始化器。
静态块在任何程序的生命周期中执行一次,没有其他方法可以调用它。
静态块示例
JavaStaticBlock.java
package com.zetcode;
public class JavaStaticBlock {
private static int i;
static {
System.out.println("Class initializer called");
i = 6;
}
public static void main(String[] args) {
System.out.println(i);
}
}
这是静态初始化器的示例。
static {
System.out.println("Class initializer called");
i = 6;
}
在静态初始化器中,我们将消息打印到控制台并初始化静态变量。
Java 静态嵌套类
静态嵌套类是可以在没有封闭类实例的情况下创建的嵌套类。 它可以访问封闭类的静态变量和方法。
静态嵌套类可以在逻辑上对仅在一个地方使用的类进行分组。 它们增加了封装并提供了更具可读性和可维护性的代码。
静态嵌套类的限制
静态嵌套类无法调用非静态方法或访问封闭类实例的非静态字段。
静态嵌套类示例
JavaStaticNestedClass.java
package com.zetcode;
public class JavaStaticNestedClass {
private static int x = 5;
static class Nested {
@Override
public String toString() {
return "This is a static nested class; x:" + x;
}
}
public static void main(String[] args) {
JavaStaticNestedClass.Nested sn = new JavaStaticNestedClass.Nested();
System.out.println(sn);
}
}
该示例展示了一个静态的嵌套类。
private static int x = 5;
这是JavaStaticNestedClass
类的私有静态变量。 可以通过静态嵌套类访问它。
static class Nested {
@Override
public String toString() {
return "This is a static nested class; x:" + x;
}
}
定义了一个静态的嵌套类。 它具有一种打印消息并引用静态x
变量的方法。
JavaStaticNestedClass.Nested sn = new JavaStaticNestedClass.Nested();
点运算符用于引用嵌套类。
Java 静态导入
静态导入是 Java 5 中引入的一项功能,该功能允许在类中定义为public static
的成员(字段和方法)在 Java 代码中使用,而无需指定定义该字段的类。
静态导入的缺点
过度使用静态导入功能会使我们的程序难以阅读和无法维护,并使用我们导入的所有静态成员污染其名称空间。
静态导入示例
JavaStaticImport.java
package com.zetcode;
import static java.lang.Math.PI;
public class JavaStaticImport {
public static void main(String[] args) {
System.out.println(PI);
}
}
在示例中,我们使用PI
常量而不使用其类。
Java 常量
static
修改器与final
修改器结合使用,还可以定义常量。 final
修饰符表示此字段的值不能更改。
public static final double PI = 3.14159265358979323846;
例如,在java.lang.Math
中,我们有一个名为PI
的常数,其值是π
的近似值(圆的周长与其直径之比)。
单例模式
单例设计模式可确保在应用的生命周期中构造一个且只有一个特定类的对象。
Singleton.java
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
在此简单的代码摘录中,我们对单个允许的对象实例具有内部静态引用。 我们通过静态方法访问对象。
在本教程中,我们介绍了 Java static
关键字。 您可能也对相关教程感兴趣: Java 中的HashMap
迭代, Java8 forEach
教程,用 Java 阅读文本文件,读写 Java 中的 ICO 图像, Java 教程,在 Java 中显示图像。
Java 中的HashMap
迭代
原文:http://zetcode.com/java/hashmapiterate/
Java 教程中的HashMap
迭代演示了如何迭代 Java 中的HashMap
。
Java HashMap
HashMap
是一个存储键值对的容器。 每个键与一个值关联。 HashMap
中的键必须唯一。 HashMap
在其他编程语言中称为关联数组或词典。 HashMaps
占用更多内存,因为每个值还有一个键。 删除和插入操作需要固定的时间。 HashMaps
可以存储空值。
Map.Entry
表示HashMap
中的键/值对。 HashMap
的entrySet()
返回包含在映射中的映射的Set
视图。 使用keySet()
方法检索一组键。
使用forEach()
的HashMap
迭代
在第一个示例中,我们使用 Java8 forEach()
方法来迭代HashMap
的键值对。 forEach()
方法对映射的每个元素执行给定的操作,直到所有元素都已处理或该操作引发异常。
HashMapForEach.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapForEach {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
items.forEach((k, v) -> {
System.out.format("key: %s, value: %d%n", k, v);
});
}
}
在代码示例中,我们使用 lambda 表达式迭代了HashMap
和forEach()
。
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
用两对创建一个HashMap
。
items.forEach((k, v) -> {
System.out.format("key: %s, value: %d%n", k, v);
});
forEach()
使代码更简洁。
使用流 API 的HashMap
迭代
流是来自源的一系列元素,支持顺序和并行聚合操作。 源可以是将数据提供给流的集合,IO 操作或数组。
HashMapStreamApi.java
package com.zetcode;
import java.util.HashMap;
public class HashMapStreamApi {
public static void main(String[] args) {
HashMap<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
items.entrySet().stream().forEach(e -> {
System.out.format("key: %s, value: %d%n", e.getKey(), e.getValue());
});
}
}
该示例使用流 API 在HashMap
上进行迭代。 我们使用entrySet()
方法获得条目集,并使用stream()
方法从条目集中获得流。 稍后,我们使用forEach()
遍历流。
使用增强的for
循环的HashMap
迭代
Java 5 中引入的增强的for
循环可用于对HashMap
进行迭代。
HashMapEnhancedFor.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class HashMapEnhancedFor {
public static void main(String[] args) {
HashMap<String, Integer> items = new HashMap();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
for (Map.Entry<String, Integer> pair: items.entrySet()) {
System.out.format("key: %s, value: %d%n", pair.getKey(), pair.getValue());
}
}
}
在该示例中,我们迭代具有增强的for
循环的HashMap
。
for (Map.Entry<String, Integer> pair: items.entrySet()) {
System.out.format("key: %s, value: %d%n", pair.getKey(), pair.getValue());
}
在每个for
周期中,都将新的键值对分配给pair
变量。
使用Iterator
的HashMap
迭代
在下面的示例中,我们使用Iterator
和Map.Entry
遍历HashMap
。
HashMapIterator.java
package com.zetcode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapIterator {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
Iterator<Map.Entry<String, Integer>> it = items.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> pair = it.next();
System.out.format("key: %s, value: %d%n", pair.getKey(),
pair.getValue());
}
}
}
在代码示例中,我们检索键值对上的迭代器,并在while
循环中对映射进行迭代。
Iterator<Map.Entry<String, Integer>> it = items.entrySet().iterator();
我们得到了迭代器对象。 首先,我们使用entrySet()
方法获得条目集,然后使用iterator()
方法从条目集中获得迭代器。
while (it.hasNext()) {
如果迭代具有更多元素,则迭代器的hasNext()
方法返回true
。
Map.Entry<String, Integer> pair = it.next();
next
方法返回下一对。
System.out.format("key: %s, value: %d", pair.getKey(),
pair.getValue());
使用getKey()
和getValue()
方法,我们可以获得键对和值。
以下示例是相同的,但是使用for
循环而不是while
。
HashMapIterator2.java
package com.zetcode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapIterator2 {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
for (Iterator<Map.Entry<String, Integer>> it = items.entrySet().iterator();
it.hasNext();) {
Map.Entry<String, Integer> pair = it.next();
System.out.format("key: %s, value: %d%n", pair.getKey(), pair.getValue());
}
}
}
在示例中,我们使用迭代器和for
循环迭代HashMap
。
在下一个示例中,我们使用HashMap
的keySet()
方法在迭代器上迭代键集,该方法返回此映射中包含的键的Set
视图。 此迭代效率较低。
HashMapIterator3.java
package com.zetcode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapIterator3 {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
Iterator<String> it = items.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
System.out.format("key: %s, value: %d%n", key,
items.get(key));
}
}
}
在示例中,我们使用迭代器迭代映射的键集。 在while
循环中使用迭代器来遍历映射的键。 以后使用该键获取相应的值。
Iterator<String> it = items.keySet().iterator();
我们得到键集的迭代器对象。
while (it.hasNext()) {
在while
循环中,我们遍历HashMap
的键。
String key = it.next();
检索下一个键。
System.out.format("key: %s, value: %d%n", key,
items.get(key));
使用get()
方法检索该值。
HashMap
迭代键
我们可能只需要遍历HashMap
的键。
HashMapKeys.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapKeys {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
Set<String> keys = items.keySet();
keys.forEach(System.out::println);
}
}
该示例迭代HashMap
的键。
Set<String> keys = items.keySet();
用keySet()
方法检索HashMap
的键,该方法返回键Set
。 键必须唯一; 因此,我们有一个Set
。 Set
是一个不包含重复元素的集合。
keys.forEach(System.out::println);
我们用forEach()
遍历键集。
HashMap
迭代值
我们可能只需要迭代HashMap
的值。
HashMapValues.java
package com.zetcode;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class HashMapValues {
public static void main(String[] args) {
Map<String, Integer> items = new HashMap<>();
items.put("coins", 5);
items.put("pens", 2);
items.put("chairs", 7);
Collection<Integer> vals = items.values();
vals.forEach(System.out::println);
}
}
该示例迭代HashMap
的值。
Collection<Integer> vals = items.values();
HashMap
的值通过values()
方法检索。
vals.forEach(System.out::println);
我们使用forEach()
遍历集合。
在包含ArrayList
的HashMap
上进行迭代
HashMap
可以包含列表作为值。 在这种情况下,我们需要一个额外的循环。
HashMapList.java
package com.zetcode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HashMapList {
public static void main(String[] args) {
Map<String, List<String>> m = new HashMap<>();
m.put("colours", Arrays.asList("red", "green", "blue"));
m.put("sizes", Arrays.asList("small", "medium", "big"));
for (Map.Entry<String, List<String>> me : m.entrySet()) {
String key = me.getKey();
List<String> values = me.getValue();
System.out.println("Key: " + key);
System.out.print("Values: ");
for (String e : values) {
System.out.printf("%s ", e);
}
System.out.println();
}
}
}
在示例中,我们迭代包含ArrayLists
作为值的HashMap
。 我们使用两个for
循环。
Map<String, List<String>> m = new HashMap<>();
m.put("colours", Arrays.asList("red", "green", "blue"));
m.put("sizes", Arrays.asList("small", "medium", "big"));
我们定义一个以ArrayLists
为值的HashMap
。
for (Map.Entry<String, List<String>> me : m.entrySet()) {
使用增强的for
循环,我们遍历条目集。 每个条目都有一个键字符串和列表值。
String key = me.getKey();
我们通过getKey()
方法获得键。
List<String> values = me.getValue();
我们用getValue()
获得列表。
for (String e : values) {
System.out.printf("%s ", e);
}
在内部for
循环中,我们遍历值列表。
HashMap
过滤
可以使用流 API 的filter()
方法过滤HashMap
。
HashMapFilter.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class HashMapFilter {
public static void main(String[] args) {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(map -> map.getValue().startsWith("B"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filteredCapitals.entrySet().forEach(System.out::println);
}
}
在此示例中,我们有一个国家及其首都的映射。 我们将映射过滤为仅包含值以 B 开头的对。
在本教程中,我们展示了如何迭代 Java 中的HashMap
。 您可能也对相关教程感兴趣: Java HashMap
教程, Java8 forEach
教程,用 Java 读取文本文件,读写 ICO Java 中的图像, Java Swing 教程,Java 教程,用 Java 显示图像。
用 Java 过滤列表
原文:http://zetcode.com/java/filterlist/
在本教程中,我们展示了如何使用 Java 过滤列表。
本教程介绍了六种过滤列表的方法。 我们使用四个不同的库:Apache Commons,Google Guava,Eclipse Collections 和 Spring core。
在所有六个示例中,我们将过滤人员列表。 Person
是具有三个属性的 Java 类:age
,name
和sex
。
使用 Java for
循环过滤列表
在第一个示例中,我们使用迭代来过滤 Java 中的列表。
com/zetcode/Person.java
package com.zetcode;
enum Gender {
MALE, FEMALE
}
public class Person {
private int age;
private String name;
private Gender sex;
public Person(int age, String name, Gender sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Person{");
sb.append("age=").append(age);
sb.append(", name='").append(name).append('\'');
sb.append(", sex=").append(sex);
sb.append('}');
return sb.toString();
}
}
我们有这个Person
bean。 我们将过滤包含这些 bean 的列表。 toString()
方法给出了 bean 的字符串表示形式。 当我们打印过滤后的元素列表时,这将很有帮助。
com/zetcode/FilterListEx.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
public class FilterListEx {
public static void main(String[] args) {
var p1 = new Person(34, "Michael", Gender.MALE);
var p2 = new Person(17, "Jane", Gender.FEMALE);
var p3 = new Person(28, "John", Gender.MALE);
var p4 = new Person(47, "Peter", Gender.MALE);
var p5 = new Person(27, "Lucy", Gender.FEMALE);
var persons = List.of(p1, p2, p3, p4, p5);
var result = new ArrayList<Person>();
for (Person person: persons) {
if (person.getAge() > 30) {
result.add(person);
}
}
System.out.println(result);
}
}
该示例过滤人员列表。 结果列表包含 30 岁以上的人。
for (Person person: persons) {
if (person.getAge() > 30) {
result.add(person);
}
}
一个for
循环用于遍历人员列表并创建一个新的具有 30 岁以上人员的人员。
[Person{age=34, name=Michael, sex=MALE}, Person{age=47, name=Peter, sex=MALE}]
这是示例的输出。
使用 Java8 流过滤列表
在下一个示例中,我们使用 Java8 流 API 来过滤列表。
com/zetcode/FilterListEx2.java
package com.zetcode;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class FilterListEx2 {
public static void main(String[] args) {
var p1 = new Person(34, "Michael", Gender.MALE);
var p2 = new Person(17, "Jane", Gender.FEMALE);
var p3 = new Person(28, "John", Gender.MALE);
var p4 = new Person(47, "Peter", Gender.MALE);
var p5 = new Person(27, "Lucy", Gender.FEMALE);
var persons = List.of(p1, p2, p3, p4, p5);
Predicate<Person> byAge = person -> person.getAge() > 30;
var result = persons.stream().filter(byAge)
.collect(Collectors.toList());
System.out.println(result);
}
}
Java 流 API 用于过滤数据以仅包含 30 岁以上的人员。
Predicate<Person> byAge = person -> person.getAge() > 30;
该谓词返回年龄大于三十的元素。
var result = persons.stream().filter(byAge)
.collect(Collectors.toList());
persons
列表用谓词过滤,并生成一个新的结果列表。
使用 Apache CollectionUtils
过滤列表
在下一个示例中,我们使用 Apache CollectionUtils
过滤数据。 它为Collection
实例提供了工具方法和修饰符。
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
我们使用这些 Maven 依赖项。 commons-lang
用于toString()
方法中使用的ToStringBuilder
。
com/zetcode/Person.java
package com.zetcode;
import org.apache.commons.lang.builder.ToStringBuilder;
enum Gender {
MALE, FEMALE
}
public class Person {
private int age;
private String name;
private Gender sex;
public Person(int age, String name, Gender sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
@Override
public String toString() {
return new ToStringBuilder(Person.class).
append("Age", age).
append("Name", name).
append("Sex", sex).
toString();
}
}
toString()
方法内部的ToStringBuilder()
对Person
bean 进行了改进。
com/zetcode/FilterListEx3.java
package com.zetcode;
import org.apache.commons.collections.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
public class FilterListEx3 {
public static void main(String[] args) {
var p1 = new Person(34, "Michael", Gender.MALE);
var p2 = new Person(17, "Jane", Gender.FEMALE);
var p3 = new Person(28, "John", Gender.MALE);
var p4 = new Person(47, "Peter", Gender.MALE);
var p5 = new Person(27, "Lucy", Gender.FEMALE);
var persons = List.of(p1, p2, p3, p4, p5);
var result = new ArrayList<>(persons);
CollectionUtils.filter(result, o -> ((Person) o).getAge() < 30);
System.out.println(result);
}
}
该示例使用 Apache Commons 库中的 Apache CollectionUtils
过滤人员 bean 列表。
var result = new ArrayList<>(persons);
将创建列表的新副本。
CollectionUtils.filter(result, o -> ((Person) o).getAge() < 30);
CollectionUtils.filter()
通过对每个元素应用谓词来过滤集合。 如果谓词返回false
,则删除该元素。
使用 Google Guava 过滤列表
在以下示例中,我们使用 Google Guava 过滤列表。 Google Guava 是 Java 通用库的开源集。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
对于 Guava 库,我们使用此依赖项。
com/zetcode/Person.java
package com.zetcode;
import com.google.common.base.MoreObjects;
enum Gender {
MALE, FEMALE
}
public class Person {
private int age;
private String name;
private Gender sex;
public Person(int age, String name, Gender sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(Person.class)
.add("Age", age)
.add("Name", name)
.add("Sex", sex)
.toString();
}
}
MoreObjects.toStringHelper()
用于改进toString()
方法。
com/zetcode/FilterListEx4.java
package com.zetcode;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
public class FilterListEx4 {
public static void main(String[] args) {
var persons = Lists.newArrayList(
new Person(34, "Michael", Gender.MALE),
new Person(17, "Jane", Gender.FEMALE),
new Person(28, "John", Gender.MALE),
new Person(47, "Peter", Gender.MALE),
new Person(27, "Lucy", Gender.FEMALE)
);
Predicate<Person> byGender = person -> person.getSex() == Gender.MALE;
var results = FluentIterable.from(persons)
.filter(byGender)
.toList();
System.out.println(results);
}
}
该代码示例过滤列表以仅包含男性。
var persons = Lists.newArrayList(
new Person(34, "Michael", Gender.MALE),
new Person(17, "Jane", Gender.FEMALE),
new Person(28, "John", Gender.MALE),
new Person(47, "Peter", Gender.MALE),
new Person(27, "Lucy", Gender.FEMALE)
);
我们使用 Guava 的newArrayList()
方法在一张照片中创建一个可变列表。
Predicate<Person> byGender = person -> person.getSex() == Gender.MALE;
对于男性,此谓词返回true
。
var results = FluentIterable.from(persons)
.filter(byGender)
.toList();
使用FluentIterable
,我们使用谓词过滤原始列表并将其放入新列表中。
使用 Eclipse 集合过滤列表
在以下示例中,我们将使用 Eclipse 集合过滤列表。
Eclipse 集合是 Java 的集合框架。 它具有与 JDK 兼容的List
,Set
和Map
实现,并具有丰富的 API,在 JDK 中找不到的其他类型(例如Bags
,Multimaps
)以及与所有与 JDK 兼容的任何工具Collections
,Arrays
,Maps
或Strings
。
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections-api</artifactId>
<version>7.1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>7.1.0</version>
</dependency>
对于程序,我们使用这两个 Maven 依赖项。
com/zetcode/FilterListEx5.java
package com.zetcode;
import org.eclipse.collections.api.block.predicate.Predicate;
import org.eclipse.collections.impl.factory.Lists;
import org.eclipse.collections.impl.utility.Iterate;
import java.util.List;
public class FilterListEx5 {
public static void main(String[] args) {
var persons = Lists.immutable.of(
new Person(34, "Michael", Gender.MALE),
new Person(17, "Jane", Gender.FEMALE),
new Person(28, "John", Gender.MALE),
new Person(47, "Peter", Gender.MALE),
new Person(27, "Lucy", Gender.FEMALE)
);
Predicate<Person> lessThan30 = (Predicate<Person>) person -> person.getAge() < 30;
var result = (List<Person>) Iterate.select(persons, lessThan30);
System.out.println(result);
}
}
该代码示例创建一个包含 30 岁以下人员的过滤列表。
Predicate<Person> lessThan30 = (Predicate<Person>) person -> person.getAge() < 30;
创建谓词以接受年龄小于 30 的元素。
var result = (List<Person>) Iterate.select(persons, lessThan30);
Iterate.select()
返回一个新集合,其中仅包含对于指定谓词求值为true
的元素。
使用 Spring 的CollectionUtils
过滤列表
在下一个示例中,我们将使用 Spring 的CollectionUtils
过滤列表。 它包含其他集合工具方法。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
该项目包含 Spring Core JAR 的 Maven 依赖项。
com/zetcode/FilterListEx6.java
package com.zetcode;
import org.springframework.cglib.core.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
public class FilterListEx6 {
public static void main(String[] args) {
var p1 = new Person(34, "Michael", Gender.MALE);
var p2 = new Person(17, "Jane", Gender.FEMALE);
var p3 = new Person(28, "John", Gender.MALE);
var p4 = new Person(47, "Peter", Gender.MALE);
var p5 = new Person(27, "Lucy", Gender.FEMALE);
var persons = Arrays.asList(p1, p2, p3, p4, p5);
var result = new ArrayList<>(persons);
CollectionUtils.filter(result, p -> ((Person) p).getAge() > 30);
System.out.println(result);
}
}
该代码示例使用 Spring 的CollectionUtils
创建一个过滤列表,其中包含 30 岁以上的人员。
var result = new ArrayList<>(persons);
与 Apache CollectionUtils
类似,将创建原始列表的副本。 该示例将修改result
列表。
CollectionUtils.filter(result, p -> ((Person) p).getAge() > 30);
CollectionUtils.filter()
方法使用给定的谓词过滤result
列表。
[Person{age=34, name=Michael, sex=MALE}, Person{age=47, name=Peter, sex=MALE}]
This is the output of the example.
在本教程中,我们使用了六种不同的方法来过滤 Java 列表。
您可能也对以下相关教程感兴趣: Java ArrayList
教程, Java 比较器和可比对象, Java 教程, Java 流过滤器 ,用 Java 读取网页 或 Google Guava 简介。
列出 Java 教程。
在 Java 中读取网页
原文:http://zetcode.com/articles/javareadwebpage/
在 Java 中读取网页是一个教程,它提供了几种读取 Java 中网页的方法。 它包含六个示例,这些示例从一个很小的网页上下载 HTTP 源。
Java 读取网页工具
Java 具有内置的工具和第三方库,用于读取/下载网页。 在示例中,我们使用 URL,JSoup,HtmlCleaner
,Apache HttpClient
,Jetty HttpClient
和 HtmlUnit。
在以下示例中,我们从 something.com 微型网页下载 HTML 源。
读取带有 URL 的网页
URL
表示一个统一资源定位符,它是指向万维网上资源的指针。
ReadWebPageEx.java
package com.zetcode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
public class ReadWebPageEx {
public static void main(String[] args) throws MalformedURLException, IOException {
BufferedReader br = null;
try {
URL url = new URL("http://www.something.com");
br = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
System.out.println(sb);
} finally {
if (br != null) {
br.close();
}
}
}
}
该代码示例读取网页的内容。
br = new BufferedReader(new InputStreamReader(url.openStream()));
openStream()
方法打开到指定 URL 的连接,并返回InputStream
以从该连接读取。 InputStreamReader
是从字节流到字符流的桥梁。 它读取字节,并使用指定的字符集将其解码为字符。 另外,BufferedReader
用于获得更好的性能。
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
使用readLine()
方法逐行读取 HTML 数据。 源被附加到StringBuilder
上。
System.out.println(sb);
最后,StringBuilder
的内容被打印到终端。
使用 JSoup 读取网页
JSoup 是流行的 Java HTML 解析器。
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.9.2</version>
</dependency>
我们已经使用了这种 Maven 依赖关系。
ReadWebPageEx2.java
package com.zetcode;
import java.io.IOException;
import org.jsoup.Jsoup;
public class ReadWebPageEx2 {
public static void main(String[] args) throws IOException {
String webPage = "http://www.something.com";
String html = Jsoup.connect(webPage).get().html();
System.out.println(html);
}
}
该代码示例使用 JSoup 下载并打印一个很小的网页。
String html = Jsoup.connect(webPage).get().html();
connect()
方法连接到指定的网页。 get()
方法发出 GET 请求。 最后,html()
方法检索 HTML 源。
使用HtmlCleaner
读取网页
HtmlCleaner
是用 Java 编写的开源 HTML 解析器。
<dependency>
<groupId>net.sourceforge.htmlcleaner</groupId>
<artifactId>htmlcleaner</artifactId>
<version>2.16</version>
</dependency>
对于此示例,我们使用htmlcleaner
Maven 依赖项。
ReadWebPageEx3.java
package com.zetcode;
import java.io.IOException;
import java.net.URL;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;
public class ReadWebPageEx3 {
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.something.com");
CleanerProperties props = new CleanerProperties();
props.setOmitXmlDeclaration(true);
HtmlCleaner cleaner = new HtmlCleaner(props);
TagNode node = cleaner.clean(url);
SimpleHtmlSerializer htmlSerializer = new SimpleHtmlSerializer(props);
htmlSerializer.writeToStream(node, System.out);
}
}
该示例使用HtmlCleaner
下载网页。
CleanerProperties props = new CleanerProperties();
props.setOmitXmlDeclaration(true);
在属性中,我们设置为省略 XML 声明。
SimpleHtmlSerializer htmlSerializer = new SimpleHtmlSerializer(props);
htmlSerializer.writeToStream(node, System.out);
SimpleHtmlSerializer
将创建结果 HTML,而不会进行任何缩进和/或压缩。
使用 Apache HttpClient
读取网页
Apache HttpClient
是 HTTP/1.1 兼容的 HTTP 代理实现。 它可以使用请求和响应过程来抓取网页。 HTTP 客户端实现 HTTP 和 HTTPS 协议的客户端。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
我们将这种 Maven 依赖关系用于 Apache HTTP 客户端。
ReadWebPageEx4.java
package com.zetcode;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
public class ReadWebPageEx4 {
public static void main(String[] args) throws IOException {
HttpGet request = null;
try {
String url = "http://www.something.com";
HttpClient client = HttpClientBuilder.create().build();
request = new HttpGet(url);
request.addHeader("User-Agent", "Apache HTTPClient");
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
System.out.println(content);
} finally {
if (request != null) {
request.releaseConnection();
}
}
}
}
在代码示例中,我们将 GET HTTP 请求发送到指定的网页并接收 HTTP 响应。 从响应中,我们读取了 HTML 源代码。
HttpClient client = HttpClientBuilder.create().build();
生成了HttpClient
。
request = new HttpGet(url);
HttpGet
是 HTTP GET 方法的类。
request.addHeader("User-Agent", "Apache HTTPClient");
HttpResponse response = client.execute(request);
执行 GET 方法并接收到HttpResponse
。
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
System.out.println(content);
从响应中,我们获得网页的内容。
使用 Jetty HttpClient
读取网页
Jetty 项目也有一个 HTTP 客户端。
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>9.4.0.M1</version>
</dependency>
这是 Jetty HTTP 客户端的 Maven 依赖项。
ReadWebPageEx5.java
package com.zetcode;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
public class ReadWebPageEx5 {
public static void main(String[] args) throws Exception {
HttpClient client = null;
try {
client = new HttpClient();
client.start();
String url = "http://www.something.com";
ContentResponse res = client.GET(url);
System.out.println(res.getContentAsString());
} finally {
if (client != null) {
client.stop();
}
}
}
}
在示例中,我们使用 Jetty HTTP 客户端获取网页的 HTML 源。
client = new HttpClient();
client.start();
创建并启动HttpClient
。
ContentResponse res = client.GET(url);
GET 请求发布到指定的 URL。
System.out.println(res.getContentAsString());
使用getContentAsString()
方法从响应中检索内容。
使用 HtmlUnit 读取网页
HtmlUnit 是用于测试基于 Web 的应用的 Java 单元测试框架。
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.23</version>
</dependency>
我们使用这种 Maven 依赖关系。
ReadWebPageEx6.java
package com.zetcode;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.IOException;
public class ReadWebPageEx6 {
public static void main(String[] args) throws IOException {
try (WebClient webClient = new WebClient()) {
String url = "http://www.something.com";
HtmlPage page = webClient.getPage(url);
WebResponse response = page.getWebResponse();
String content = response.getContentAsString();
System.out.println(content);
}
}
}
该示例下载一个网页并使用 HtmlUnit 库进行打印。
在本文中,我们使用各种工具(包括 URL,JSoup,HtmlCleaner
,Apache HttpClient
,Jetty HttpClient
和 HtmlUnit)在 Java 中抓取了一个网页。
您可能也对以下相关教程感兴趣: Java 教程, Java Servlet 读取网页,如何使用 Java 读取文本文件 ,[发送 HTTP GET POST 请求 ]使用 Java](/articles/javareadtext/),使用 Java8 的StringJoiner
来连接字符串,Jetty 教程或 Google Guava 简介。
Java 控制台应用
原文:http://zetcode.com/java/console/
Java 控制台应用教程显示了如何创建 Java 控制台应用。 该应用计算一些统计信息。
Java 控制台示例
以下示例创建一个 Java 控制台应用,该应用从 CSV 文件读取数据并计算一些基本统计信息。
该示例使用 Apache Commons 库来解析命令行参数,进行数学运算和转换数据。 OpenCSV 库用于读取 CSV 数据。
src/resources/data.csv
2.3, 3.5, 5, 6.7, 3.2, 1.2, 6.7, 7.8
4.5, 2.1, 6.6, 8.7, 3.2, 1.0, 1.2, 3
这是数据文件。 文件名将是我们程序的控制台参数。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ JavaStatsEx.java
│ │ MyStatsApp.java
│ └───resources
│ data.txt
└───test
└───java
这是项目结构。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>javastatsex</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
</dependencies>
</project>
在pom.xml
文件中,我们定义了应用的依赖项。 commons-cli
工件用于解析命令行参数,opencsv
用于读取 CSV 数据,commons-math
用于统计计算,commons-lang3
用于将列表转换为数组。
exec-maven-plugin
从 Maven 执行 Java 程序。 在arguments
标签中,我们为应用提供了选项和文件名。
com/zetcode/JavaStatsEx.java
package com.zetcode;
/**
* Starter class for MyStats application.
*
* @author janbodnar
*/
public class JavaStatsEx {
/**
* Application entry point.
*
* @param args application command line arguments
*/
public static void main(String[] args) {
var app = new MyStatsApp();
app.run(args);
}
}
JavaStatsEx
是应用入口点。 它创建MyStatsApp
的实例,并将其传递给应用参数。
com/zetcode/MyStatsApp.java
package com.zetcode;
import com.opencsv.CSVReaderBuilder;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.math3.stat.StatUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
/**
* MyStatsApp is a simple console application which computes
* basic statistics of a series of data values. The application takes
* a file of data as its single argument.
*
* @author janbodnar
*/
public class MyStatsApp {
/**
* Runs the application
*
* @param args an array of String arguments to be parsed
*/
public void run(String[] args) {
CommandLine line = parseArguments(args);
if (line.hasOption("filename")) {
System.out.println(line.getOptionValue("filename"));
String fileName = line.getOptionValue("filename");
double[] data = readData(fileName);
calculateAndPrintStats(data);
} else {
printAppHelp();
}
}
/**
* Parses application arguments
*
* @param args application arguments
* @return <code>CommandLine</code> which represents a list of application
* arguments.
*/
private CommandLine parseArguments(String[] args) {
Options options = getOptions();
CommandLine line = null;
CommandLineParser parser = new DefaultParser();
try {
line = parser.parse(options, args);
} catch (ParseException ex) {
System.err.println("Failed to parse command line arguments");
System.err.println(ex.toString());
printAppHelp();
System.exit(1);
}
return line;
}
/**
* Reads application data from a file
*
* @param fileName file of application data
* @return array of double values
*/
private double[] readData(String fileName) {
var data = new ArrayList<Double>();
double[] mydata = null;
try (var reader = Files.newBufferedReader(Paths.get(fileName));
var csvReader = new CSVReaderBuilder(reader).build()) {
String[] nextLine;
while ((nextLine = csvReader.readNext()) != null) {
for (String e : nextLine) {
data.add(Double.parseDouble(e));
}
}
mydata = ArrayUtils.toPrimitive(data.toArray(new Double[0]));
} catch (IOException ex) {
System.err.println("Failed to read file");
System.err.println(ex.toString());
System.exit(1);
}
return mydata;
}
/**
* Generates application command line options
*
* @return application <code>Options</code>
*/
private Options getOptions() {
var options = new Options();
options.addOption("f", "filename", true, "file name to load data from");
return options;
}
/**
* Prints application help
*/
private void printAppHelp() {
Options options = getOptions();
var formatter = new HelpFormatter();
formatter.printHelp("JavaStatsEx", options, true);
}
/**
* Calculates and prints data statistics
*
* @param data input data
*/
private void calculateAndPrintStats(double[] data) {
System.out.format("Geometric mean: %f%n", StatUtils.geometricMean(data));
System.out.format("Arithmetic mean: %f%n", StatUtils.mean(data));
System.out.format("Max: %f%n", StatUtils.max(data));
System.out.format("Min: %f%n", StatUtils.min(data));
System.out.format("Sum: %f%n", StatUtils.sum(data));
System.out.format("Variance: %f%n", StatUtils.variance(data));
}
}
这是MyStatsApp
。
CommandLine line = parseArguments(args);
parseArguments()
方法解析命令行参数。 它返回CommandLine
,它代表针对Options
描述符解析的参数列表。
if (line.hasOption("filename")) {
System.out.println(line.getOptionValue("filename"));
String fileName = line.getOptionValue("filename");
double[] data = readData(fileName);
calculateAndPrintStats(data);
} else {
printAppHelp();
}
该应用具有强制性的文件名选项,该选项指向要读取的文件并从中计算统计信息。 如果不存在,我们将提供应用帮助消息。
Options options = getOptions();
getOptions()
方法返回应用的选项。
try {
line = parser.parse(options, args);
} catch (ParseException ex) {
System.err.println("Failed to parse command line arguments");
System.err.println(ex.toString());
printAppHelp();
System.exit(1);
}
return line;
CommandLineParser
解析命令行参数。 如果存在ParseException
,则应用退出。 解析器在CommandLine
对象中返回已解析的参数。
try (var reader = Files.newBufferedReader(Paths.get(fileName));
var csvReader = new CSVReaderBuilder(reader).build()) {
CSVReader
用于读取 CSV 数据。
String[] nextLine;
while ((nextLine = csvReader.readNext()) != null) {
for (String e : nextLine) {
data.add(Double.parseDouble(e));
}
}
在此while
循环中,我们逐行读取 CSV 文件,并将数据解析为Double
值列表。
mydata = ArrayUtils.toPrimitive(data.toArray(new Double[0]));
我们需要原始数据类型来计算统计信息。 因此,我们将列表转换为原始双精度值数组。 ArrayUtils
来自 Apache Commons Lang 库。
private Options getOptions() {
var options = new Options();
options.addOption("f", "filename", true, "file name to load data from");
return options;
}
getOptions()
提供应用选项。
private void printAppHelp() {
Options options = getOptions();
var formatter = new HelpFormatter();
formatter.printHelp("JavaStatsEx", options, true);
}
printAppHelp()
打印应用的帮助。 它使用HelpFormatter
来完成工作。
private void calculateAndPrintStats(double[] data) {
System.out.format("Geometric mean: %f%n", StatUtils.geometricMean(data));
System.out.format("Arithmetic mean: %f%n", StatUtils.mean(data));
System.out.format("Max: %f%n", StatUtils.max(data));
System.out.format("Min: %f%n", StatUtils.min(data));
System.out.format("Sum: %f%n", StatUtils.sum(data));
System.out.format("Variance: %f%n", StatUtils.variance(data));
}
使用StatUtils()
,我们可以计算一些统计数据。 StatUtils()
采用 Java 数组作为参数。
src/main/resources/data.txt
Geometric mean: 3.412562
Arithmetic mean: 4.168750
Max: 8.700000
Min: 1.000000
Sum: 66.700000
Variance: 6.158292
这是输出。
在本教程中,我们创建了一个简单的 Java 控制台应用,该应用从 CSV 文件计算基本统计信息。
列出所有 Java 教程。
Java 集合的便利工厂方法
原文:http://zetcode.com/articles/jep269/
本文介绍了 JDK 9 中引入的用于集合的便捷工厂方法。JEP(Java 增强过程)269 引入了新的 API,以使创建具有少量元素的集合和映射实例更加方便。
目的是减轻 Java 编程语言中没有集合字面值的痛苦。 故意将 API 保持为最小。
它在List
,Set
和Map
接口上包含新的静态工厂方法,用于创建集合的不可修改实例。
安装 JDK 9 EA
我们从 jdk9.java.net/download/ 下载 JDK 9 早期访问。
$ tar vzfx jdk-9-ea+131_linux-x64_bin.tar.gz
在 Linux 上,我们解压缩jdk-9-ea+131_linux-x64_bin.tar.gz
文件。
$ cd jdk-9/
$ ./bin/java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+131)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+131, mixed mode)
我们移至根目录并显示 Java 版本。
目前,NetBeans 和 Eclipse 都不支持 JDK 9。 因此,我们将从命令行运行示例。
有三种新的静态重载方法:
List.of()
Set.of()
Map.of()
该方法创建各个集合的不可修改实例。
列表示例
第一个示例使用新的 API 创建一个列表。 列表是一个简单的有序集合,允许重复的元素。
$ tree
.
└── com
└── zetcode
└── ListExample.java
2 directories, 1 file
我们有这个项目目录结构。
ListExample.java
package com.zetcode;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
List<String> fruits = List.of("apple", "banana", "plum", "lemon");
System.out.println(fruits);
String[] items = {"coin", "pen", "bottle", "spoon"};
List<String> listOfItems = List.of(items);
System.out.println(listOfItems);
}
}
在示例中,我们使用新的List.of()
方法调用创建了两个字符串列表。
List<String> fruits = List.of("apple", "banana", "plum", "lemon");
创建一个新列表。 这些项目被指定为List.of()
参数。
String[] items = {"coin", "pen", "bottle", "spoon"};
List<String> listOfItems = List.of(items);
List.of()
也可以将数组作为参数。
$ ~/bin/jdk1.9/bin/javac -d bin com/zetcode/ListExample.java
我们编译代码示例。 二进制文件放入bin
目录。
$ ~/bin/jdk1.9/bin/java -cp bin com.zetcode.ListExample
[apple, banana, plum, lemon]
[coin, pen, bottle, spoon]
我们运行示例。 这两个列表将打印到控制台。
集合示例
在下面的示例中,我们显示了Set
集合的新 API。 集合是不包含重复元素的集合。
SetExample.java
package com.zetcode;
import java.util.Set;
import java.util.TreeSet;
public class SetExample {
public static void main(String[] args) {
Set<String> colours = Set.of("blue", "red", "green", "yellow");
System.out.println(colours);
String[] names = {"Jane", "Paul", "Robin", "Susan",
"Monica", "Jan", "Peter"};
TreeSet<String> setOfnames = new TreeSet<String>(Set.of(names));
System.out.println(setOfnames);
}
}
创建两个集合; 第二个按字母顺序排序。
Set<String> colours = Set.of("blue", "red", "green", "yellow");
通过Set.of()
方法调用创建一个新集合。
String[] names = {"Jane", "Paul", "Robin", "Susan",
"Monica", "Jan", "Peter"};
TreeSet<String> setOfnames = new TreeSet<String>(Set.of(names));
要创建排序集,我们将创建的集传递给TreeSet
。
$ ~/bin/jdk1.9/bin/javac -d bin com/zetcode/SetExample.java
$ ~/bin/jdk1.9/bin/java -cp bin com.zetcode.SetExample
[yellow, red, green, blue]
[Jan, Jane, Monica, Paul, Peter, Robin, Susan]
我们编译并运行该示例。
映射示例
接下来的两个示例展示了Map
集合的新 API。 映射是一个包含唯一键/值对的集合。
MapExample.java
package com.zetcode;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
Map<String, Integer> items = Map.of("coins", 12, "chairs", 4, "pens", 2);
items.entrySet().stream().forEach(System.out::println);
}
}
Map.of()
方法使用两个键值对创建一个新映射。
$ ~/bin/jdk1.9/bin/javac -d bin com/zetcode/MapExample.java
$ ~/bin/jdk1.9/bin/java -cp bin com.zetcode.MapExample
coins=12
chairs=4
pens=2
我们编译并运行该程序。
在第二个示例中,我们使用Map.entry()
创建映射元素。 映射条目是一个键值对。
MapExample2.java
package com.zetcode;
import java.util.Map;
import static java.util.Map.entry;
public class MapExample2 {
public static void main(String[] args) {
Map<Integer,String> map = Map.ofEntries(
entry(1, "A"),
entry(2, "B"),
entry(3, "C"),
entry(4, "D")
);
map.entrySet().stream().forEach(System.out::println);
}
}
使用Map.ofEntries()
方法创建一个新的条目映射。
$ ~/bin/jdk1.9/bin/javac -d bin com/zetcode/MapExample2.java
$ ~/bin/jdk1.9/bin/java -cp bin com.zetcode.MapExample2
1=A
2=B
3=C
4=D
We compile and run the program.
在本文中,我们研究了即将发布的 JDK 9 中的新集合 API。
您可能也对以下相关教程感兴趣: Java 教程, Java 局部变量类型推断,用 Java8 的StringJoiner
连接字符串或 Google Guava 。
Google Guava 简介
原文:http://zetcode.com/articles/guava/
本教程是 Guava 库的简介。 我们看一下 Guava 库的一些有趣的功能。
Guava
Google Guava 是 Java 通用库的开源集合,主要由 Google 工程师开发。 Google 有许多 Java 项目。 Guava 是解决那些项目中遇到的许多常见问题的解决方案,其中包括集合,数学,函数习语,输入&输出和字符串等领域。
Guava 的某些功能已经包含在 JDK 中。 例如String.join()
方法已引入 JDK 8。
Guava Maven 依赖
在我们的示例中,我们使用以下 Maven 依赖关系。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
Guava 初始化集合
Guava 允许在一行中初始化集合。 JDK 8 不支持集合字面值。
InitializeCollectionEx.java
package com.zetcode.initializecollectionex;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;
public class InitializeCollectionEx {
public static void main(String[] args) {
Map items = ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1);
items.entrySet()
.stream()
.forEach(System.out::println);
List<String> fruits = Lists.newArrayList("orange", "banana", "kiwi",
"mandarin", "date", "quince");
for (String fruit: fruits) {
System.out.println(fruit);
}
}
}
在示例中,我们使用 Guava 的工厂方法创建映射和列表。
Map items = ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1);
使用ImmutableMap.of()
方法创建一个新映射。
List<String> fruits = Lists.newArrayList("orange", "banana", "kiwi",
"mandarin", "date", "quince");
使用Lists.newArrayList()
方法创建一个新的字符串列表。
coin=3
glass=4
pencil=1
orange
banana
kiwi
mandarin
date
quince
这是示例的输出。
Guava MoreObjects.toStringHelper()
MoreObjects.toStringHelper()
有助于轻松创建具有一致格式的toString()
方法,它使我们可以控制所包含的字段。
Car.java
package com.zetcode.tostringex.beans;
import com.google.common.base.MoreObjects;
public class Car {
private long Id;
private String Name;
private int Price;
public Car(long Id, String Name, int Price) {
this.Id = Id;
this.Name = Name;
this.Price = Price;
}
public long getId() {
return Id;
}
public void setId(long Id) {
this.Id = Id;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public int getPrice() {
return Price;
}
public void setPrice(int Price) {
this.Price = Price;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(Car.class)
.add("id", Id)
.add("name", Name)
.add("price", Price)
.toString();
}
}
这是一个Car
bean。 它包含toString()
方法,该方法给出对象的字符串表示形式。
@Override
public String toString() {
return MoreObjects.toStringHelper(Car.class)
.add("id", Id)
.add("name", Name)
.add("price", Price)
.toString();
}
除了使用字符串之外,我们还提供了MoreObjects.toStringHelper()
方法更简洁的解决方案。
ToStringEx.java
package com.zetcode.tostringex;
import com.zetcode.tostringex.beans.Car;
public class ToStringEx {
public static void main(String[] args) {
Car car1 = new Car(1, "Audi", 52642);
Car car2 = new Car(2, "Mercedes", 57127);
Car car3 = new Car(3, "Skoda", 9000);
System.out.println(car1);
System.out.println(car2);
System.out.println(car3);
}
}
我们创建三个汽车对象,并将它们传递给System.out.println()
方法。 该方法调用对象的toString()
方法。
Car{id=1, name=Audi, price=52642}
Car{id=2, name=Mercedes, price=57127}
Car{id=3, name=Skoda, price=9000}
This is the output of the example.
Guava FluentIterable
FluentIterable
提供了一个强大而简单的 API,可以流畅地操作Iterable
实例。 它允许我们以各种方式过滤和转换集合。
Car.java
package com.zetcode.fluentiterable.beans;
import com.google.common.base.MoreObjects;
public class Car {
private long Id;
private String Name;
private int Price;
public Car(long Id, String Name, int Price) {
this.Id = Id;
this.Name = Name;
this.Price = Price;
}
public long getId() {
return Id;
}
public void setId(long Id) {
this.Id = Id;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public int getPrice() {
return Price;
}
public void setPrice(int Price) {
this.Price = Price;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(Car.class)
.add("id", Id)
.add("name", Name)
.add("price", Price)
.toString();
}
}
在此示例中,我们有一个Car
bean。
FluentIterableEx.java
package com.zetcode.fluentiterable;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.zetcode.fluentiterable.beans.Car;
import java.util.List;
public class FluentIterableEx {
public static void main(String[] args) {
List<Car> cars = Lists.newArrayList(new Car(1, "Audi", 52642),
new Car(2, "Mercedes", 57127), new Car(3, "Skoda", 9000),
new Car(4, "Volvo", 29000));
Predicate<Car> byPrice = car -> car.getPrice() <= 30000;
List<String> results = FluentIterable.from(cars)
.filter(byPrice)
.transform(Functions.toStringFunction())
.toList();
System.out.println(results);
}
}
在代码示例中,我们有一个汽车对象列表。 我们通过将列表减少为仅适用于价格低于 30000 辆的汽车来对其进行改造。
List<Car> cars = Lists.newArrayList(new Car(1, "Audi", 52642),
new Car(2, "Mercedes", 57127), new Car(3, "Skoda", 9000),
new Car(4, "Volvo", 29000));
创建Car
对象的列表。 JDK 中没有集合字面值。 我们使用 Guava 中的Lists.newArrayList()
初始化列表。
Predicate<Car> byPrice = car -> car.getPrice() <= 30000;
创建了Predicate
。 谓词是一个返回布尔值的函数。 该谓词确定汽车是否比 30000 便宜。
List<String> results = FluentIterable.from(cars)
.filter(byPrice)
.transform(Functions.toStringFunction())
.toList();
从cars
集合创建一个FluentIterable
。 谓词函数应用于FluentIterable
。 检索到的元素将转换为元素列表; 元素是从toString()
函数返回的字符串。
[Car{id=3, name=Skoda, price=9000}, Car{id=4, name=Volvo, price=29000}]
This is the output of the example.
Guava 谓词
一般而言,谓词是关于正确或错误的陈述。
如果要测试的对象引用不是null
,则Predicates.notNull()
返回一个求值为true
的谓词。
PredicateEx.java
package com.zetcode.predicateex;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.List;
public class PredicateEx {
public static void main(String[] args) {
List<Integer> values = Lists.newArrayList(3, null, 4, 7,
8, null, 7);
Iterable<Integer> filtered = Iterables.filter(values,
Predicates.notNull());
for (Integer i: filtered) {
System.out.println(i);
}
}
}
在第一个示例中,我们使用谓词从集合中排除null
值。
List<Integer> values = Lists.newArrayList(3, null, 4, 7,
8, null, 7);
使用 Guava 的Lists.newArrayList()
,我们创建了Integer
值的列表。 该列表包含两个nulls
。
Iterable<Integer> filtered = Iterables.filter(values,
Predicates.notNull());
我们通过应用Predicates.notNull()
过滤值。 Iterables.filter
返回一个可迭代的对象。
for (Integer i: filtered) {
System.out.println(i);
}
我们遍历过滤列表并打印其元素。
3
4
7
8
7
This is the output of the example.
第二个示例按特定的文本模式过滤集合。 在编程中,谓词通常用于过滤数据。
PredicateEx2.java
package com.zetcode.predicateex;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
public class PredicateEx2 {
public static void main(String[] args) {
List<String> items = Lists.newArrayList("coin", "book",
"cup", "purse", "bottle");
Collection<String> result = Collections2.filter(items,
Predicates.containsPattern("o"));
for (String item: result) {
System.out.println(item);
}
}
}
该代码示例创建一个项目列表,然后按特定模式过滤该列表。
Collection<String> result = Collections2.filter(items,
Predicates.containsPattern("o"));
Predicates.containsPattern()
返回一个谓词,该谓词查找包含字符"o"
的项目。 谓词将传递给Collections2.filter()
方法。
coin
book
bottle
这三个词符合标准。
Guava readLines()
Files.readLines()
允许一次性读取文件中的所有行。
图:NetBeans 项目结构
该图显示了项目结构在 NetBeans 中的外观。
balzac.txt
Honoré de Balzac, original name Honoré Balzac (born May 20, 1799, Tours,
France—died August 18, 1850, Paris) French literary artist who produced
a vast number of novels and short stories collectively called
La Comédie humaine (The Human Comedy). He helped to establish the traditional
form of the novel and is generally considered to be one of the greatest
novelists of all time.
我们在src/main/resources
目录中有此文本文件。
ReadingLinesEx.java
package com.zetcode.readinglinesex;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class ReadingLinesEx {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/balzac.txt";
List<String> lines = Files.readLines(new File(fileName),
Charsets.UTF_8);
for (String line: lines) {
System.out.println(line);
}
}
}
该示例从balzac.txt
文件读取所有行,并将它们打印到控制台。
String fileName = "src/main/resources/balzac.txt";
文件名位于src/main/resource
目录中。
List<String> lines = Files.readLines(new File(fileName),
Charsets.UTF_8);
使用Files.readLines()
方法,我们从balzac.txt
文件中读取所有行。 这些行存储在字符串列表中。
for (String line: lines) {
System.out.println(line);
}
我们遍历列表并打印其元素。
使用 Guava 创建一个新文件
Files.touch()
方法用于创建新文件或更新现有文件上的时间戳。 该方法类似于 Unix touch
命令。
TouchFileEx.java
package com.zetcode.touchfileex;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
public class TouchFileEx {
public static void main(String[] args) throws IOException {
String newFileName = "newfile.txt";
Files.touch(new File(newFileName));
}
}
该示例在项目的根目录中创建newfile.txt
。
用 Guava 写入文件
Files.write()
方法将数据写入文件。
WriteToFileEx.java
package com.zetcode.writetofileex;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
public class WriteToFileEx {
public static void main(String[] args) throws IOException {
String fileName = "fruits.txt";
File file = new File(fileName);
String content = "banana, orange, lemon, apple, plum";
Files.write(content.getBytes(), file);
}
}
该示例将由水果名称组成的字符串写入fruits.txt
文件。 该文件在项目根目录中创建。
用 Guava 连接字符串
Joiner
用分隔符将文本片段(指定为数组,Iterable
,可变参数或Map
)连接在一起。
StringJoinerEx.java
package com.zetcode.stringjoinerex;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import java.util.List;
public class StringJoinerEx {
public static void main(String[] args) {
List<String> myList = Lists.newArrayList("8", "2", "7", "10");
String result = Joiner.on(",").join(myList);
System.out.println(result);
}
}
在示例中,我们用逗号将列表中的元素连接起来。
8,2,7,10
This is the output of the example.
用 Guava 分割字符串
Splitter
通过识别分隔符序列的出现,从输入字符串中提取不重叠的子字符串。
StringSplitterEx.java
package com.zetcode.stringsplitterex;
import com.google.common.base.Splitter;
import java.util.List;
public class StringSplitterEx {
public static void main(String[] args) {
String input = "There is a dog in the garden.";
List<String> words = Splitter.on(" ").splitToList(input);
for (String word: words) {
System.out.println(word);
}
}
}
该示例使用Splitter
将句子拆分为单词。
String input = "There is a dog in the garden.";
我们有一个由七个词组成的句子。
List<String> words = Splitter.on(" ").splitToList(input);
分隔符是一个空格字符。 splitToList()
方法将输入拆分为字符串列表。
第二个示例将输入分为三个子字符串。
StringSplitterEx2.java
package com.zetcode.stringsplitterex2;
import com.google.common.base.Splitter;
import java.util.List;
public class StringSplitterEx2 {
public static void main(String[] args) {
String input = "coin, pencil, chair, bottle, soap";
List<String> words = Splitter.on(",")
.trimResults()
.limit(3)
.splitToList(input);
for (String word: words) {
System.out.println(word);
}
}
}
此外,还对单词进行了修剪。
coin
pencil
chair, bottle, soap
这是输出。
Guava 先决条件
前提条件是简单的静态方法,将在我们自己的方法开始时调用它们以验证正确的参数和状态。 该方法在失败时抛出IllegalArgumentException
。
PreconditionsEx.java
package com.zetcode.preconditionex;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.base.Splitter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
public class PreconditionsEx {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter items: ");
String input = br.readLine();
List<String> items = Splitter.on(" ").splitToList(input);
OutputItems(items);
}
public static void OutputItems(List<String> items) {
checkArgument(items != null, "The list must not be null");
checkArgument(!items.isEmpty(), "The list must not be empty");
for (String item: items) {
System.out.println(item);
}
}
}
该示例使用两个前提条件。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter items: ");
String input = br.readLine();
我们从用户那里读取输入。 我们希望有一个单词列表。
List<String> items = Splitter.on(" ").splitToList(input);
OutputItems(items);
将指定的单词拆分为一个列表,并将该列表传递给OutputItems()
方法
checkArgument(items != null, "The list must not be null");
checkArgument(!items.isEmpty(), "The list must not be empty");
在OutputItems()
方法中,我们检查列表是否不为空。 使用checkArgument()
方法,我们可以确保表达式的有效性; 例如该列表不为空。
用 Guava 计算阶乘
Guava 还提供用于进行数学计算的工具。 BigIntegerMath.factorial()
计算阶乘。
FactorialEx.java
package com.zetcode.factorialex;
import com.google.common.math.BigIntegerMath;
public class FactorialEx {
public static void main(String[] args) {
System.out.println(BigIntegerMath.factorial(100));
}
}
该示例显示数字 100 的阶乘。
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
This is the output of the example.
用 Guava 计算二项式
BigIntegerMath.binomial()
返回n
和k
的二项式系数。
FactorialEx.java
package com.zetcode.binomialex;
import com.google.common.math.BigIntegerMath;
import java.math.BigInteger;
public class BinomialEx {
public static void main(String[] args) {
BigInteger bigInt = BigIntegerMath.binomial(4, 2);
System.out.println(bigInt);
}
}
该示例显示 4 和 2 的二项式。
Guava CharMatcher
CharMatcher
提供了一些基本的文本处理方法。
CharMatcherEx.java
package com.zetcode.charmatcherex;
import com.google.common.base.CharMatcher;
public class CharMatcherEx {
public static void main(String[] args) {
String input = "Peter17";
CharMatcher matcher = CharMatcher.JAVA_LETTER;
String result = matcher.retainFrom(input);
System.out.println(result);
}
}
该示例从输入字符串中删除所有非字母字符。 retainFrom()
方法按顺序返回包含字符序列的所有匹配字符的字符串。
Peter
两位数字被删除。
在第二个示例中,我们计算输入字符串中的字符数。
CharMatcherEx2.java
package com.zetcode.charmatcherex2;
import com.google.common.base.CharMatcher;
public class CharMatcherEx2 {
public static void main(String[] args) {
String input = "Beautiful sunny day";
int n1 = CharMatcher.is('n').countIn(input);
System.out.format("Number of n characters: %d%n", n1);
int n2 = CharMatcher.is('i').countIn(input);
System.out.format("Number of i characters: %d", n2);
}
}
该示例计算输入字符串中'n'和'i'字符的数量。
int n1 = CharMatcher.is('n').countIn(input);
countIn()
方法返回在字符序列中找到的匹配字符数。
Number of n characters: 2
Number of i characters: 1
This is the output of the example.
CharMatcher.whitespace()
确定字符是否为空格。
CharMatcherEx3.java
package com.zetcode.charmatcherex3;
import com.google.common.base.CharMatcher;
public class CharMatcherEx3 {
public static void main(String[] args) {
String input = " yogurt \t";
String result = CharMatcher.whitespace().trimFrom(input);
System.out.println(input + " and bread" );
System.out.println(result + " and bread");
}
}
在第三个示例中,我们从字符串中删除空格。
String result = CharMatcher.whitespace().trimFrom(input);
空格从输入字符串中删除。
yogurt and bread
yogurt and bread
This is the output of the example.
Guava Range
Range
可以轻松创建各种范围。 范围或间隔定义了连续值范围周围的边界; 例如 1 到 10 之间的整数(含 1 和 10)。
RangeEx.java
package com.zetcode.rangeex;
import com.google.common.collect.Range;
public class RangeEx {
public static void main(String[] args) {
Range<Integer> range1 = Range.closed(3, 8);
System.out.println(range1);
Range<Integer> range2 = Range.openClosed(3, 8);
System.out.println(range2);
Range<Integer> range3 = Range.closedOpen(3, 8);
System.out.println(range3);
}
}
在示例中,我们创建了三个整数间隔。
[3‥8]
(3‥8]
[3‥8)
This is the output of the example.
在本文中,我们使用了 Google Guava 库。
您可能也对以下相关教程感兴趣:用 Java 阅读文本文件, Java 教程,用 Java 过滤列表, Java8 的StringJoiner
或 Opencsv 教程。
OpenCSV 教程
原文:http://zetcode.com/articles/opencsv/
在 Opencsv 教程中,我们展示了如何与 Opencsv 库一起使用,该库用于在 Java 中读写 CSV 文件。 我们提供了一些代码示例,可在 Java 中使用 CSV。 该教程的源代码也可以从作者的 Github 仓库中获得。
CSV(逗号分隔值)格式是在电子表格和数据库中使用的非常流行的导入和导出格式。
CSV 文件中的每一行都是一个数据记录。 每个记录由一个或多个字段组成,用逗号分隔。 尽管 CSV 格式是一种非常简单的格式,但还是有许多差异,例如不同的定界符,换行或引号字符。
Opencsv 库
Opencsv 是一个非常简单的 Java CSV 解析器库。 它的开发是由于缺乏商业友好许可证。
<dependencies>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.1</version>
</dependency>
</dependencies>
这是 Opencsv 的 Maven 依赖关系。
OpenCSV 读取数据
以下示例从 CSV 文件读取数字。
$ tree
.
├── nbactions.xml
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ └── OpenCSVReadEx.java
│ └── resources
│ └── numbers.csv
└── test
└── java
这是项目结构。
numbers.csv
3,5,6,2,1,7,8
4,5,7,3,2,8,9
numbers.csv
文件中有两个数据记录。
OpenCSVReadEx.java
package com.zetcode;
import com.opencsv.CSVReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class OpenCSVReadEx {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/numbers.csv";
try (FileInputStream fis = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(fis,
StandardCharsets.UTF_8);
CSVReader reader = new CSVReader(isr)) {
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
for (String e : nextLine) {
System.out.format("%s ", e);
}
}
}
}
}
该示例从numbers.csv
文件中读取数字并将其打印到控制台。
String fileName = "src/main/resources/numbers.csv";
该文件位于src/main/resources
目录中。
try (FileInputStream fis = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(fis,
StandardCharsets.UTF_8);
CSVReader reader = new CSVReader(isr)) {
CSVReader
是用于读取 CSV 文件的类。
while ((nextLine = reader.readNext()) != null) {
for (String e: nextLine) {
System.out.format("%s ", e);
}
}
我们遍历读取器并将值打印到终端。 readNext()
方法从缓冲区读取下一行,并转换为字符串数组。
3 5 6 2 1 7 8 4 5 7 3 2 8 9
这是程序的输出。
使用不同的分隔符的 OpenCSV 读取
尽管有 CSV 文件的名称,但也可以用逗号以外的分隔符分隔 CSV 文件。 下面的示例显示如何读取由竖线分隔的数字字符。
此示例使用 Gradle 工具构建。
$ tree
.
├── build.gradle
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ └── OpenCSVReadEx2.java
│ └── resources
│ └── numbers.csv
└── test
├── java
└── resources
我们展示了项目结构。
settings.gradle
rootProject.name = 'OpenCSVReadEx2'
这是 Gradle 设置文件。
build.gradle
apply plugin: 'application'
archivesBaseName = "readnumbers2"
version = '1.0'
mainClassName = "com.zetcode.OpenCSVReadEx2"
sourceCompatibility = '1.8'
compileJava.options.encoding = 'UTF-8'
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.opencsv', name: 'opencsv', version: '4.1'
}
这是 Gradle 构建文件。
numbers.csv
1|2|3|4|5
6|7|3|9|8
9|1|1|0|2
我们有三行数字,中间用|分隔。 字符。
OpenCSVReadEx2.java
package com.zetcode;
import com.opencsv.CSVParser;
import com.opencsv.CSVParserBuilder;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class OpenCSVReadEx2 {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/numbers.csv";
Path myPath = Paths.get(fileName);
CSVParser parser = new CSVParserBuilder().withSeparator('|').build();
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8);
CSVReader reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build()) {
List<String[]> rows = reader.readAll();
for (String[] row : rows) {
for (String e : row) {
System.out.format("%s ", e);
}
System.out.println();
}
}
}
}
该示例从numbers.csv
文件中读取值,并将其打印到控制台。
CSVParser parser = new CSVParserBuilder().withSeparator('|').build();
创建具有特定解析器字符的CSVParser
。
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8);
CSVReader reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build()) {
用CSVReaderBuilder
创建一个CSVReader
。
List<String[]> rows = reader.readAll();
我们使用readAll()
方法将所有元素读入列表中。 此方法不应用于大文件。
$ gradle build
$ gradle run
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
1 2 3 4 5
6 7 3 9 8
9 1 1 0 2
我们构建并运行该示例。
OpenCSV 写入数据
CSVWriter
类用于将数据写入 CSV 文件。
OpenCSVWriteEx.java
package com.zetcode;
import com.opencsv.CSVWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
public class OpenCSVWriteEx {
public static void main(String[] args) throws IOException {
String[] entries = { "book", "coin", "pencil", "cup" };
String fileName = "src/main/resources/items.csv";
try (FileOutputStream fos = new FileOutputStream(fileName);
OutputStreamWriter osw = new OutputStreamWriter(fos,
StandardCharsets.UTF_8);
CSVWriter writer = new CSVWriter(osw)) {
writer.writeNext(entries);
}
}
}
该示例将数据从数组写入items.csv
文件。 该文件将写入项目根目录。 writeNext()
方法将元素数组写入文件。
在下一个代码示例中,我们将所有数据一次性写入。
OpenCSVWriteEx2.java
package com.zetcode;
import com.opencsv.CSVWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class OpenCSVWriteEx2 {
public static void main(String[] args) throws IOException {
String[] items1 = {"book", "coin", "pencil"};
String[] items2 = {"pen", "chair", "lamp"};
String[] items3 = {"ball", "bowl", "spectacles"};
List<String[]> entries = new ArrayList<>();
entries.add(items1);
entries.add(items2);
entries.add(items3);
String fileName = "src/main/resources/items.csv";
try (FileOutputStream fos = new FileOutputStream(fileName);
OutputStreamWriter osw = new OutputStreamWriter(fos,
StandardCharsets.UTF_8);
CSVWriter writer = new CSVWriter(osw)) {
writer.writeAll(entries);
}
}
}
该示例使用writeAll()
方法将数组列表写入items.csv
文件。
将 SQL 数据转换为 CSV 文件
以下示例从数据库表中检索数据并将其写入 CSV 文件。 我们使用 MySQL 数据库。 有关 MySQL 和 MySQL Java 编程的更多信息,请参见 MySQL 教程和 MySQL Java 教程。
cars_mysql.sql
-- SQL for the Cars table
CREATE TABLE Cars(Id BIGINT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(150),
Price INTEGER);
INSERT INTO Cars(Name, Price) VALUES('Audi', 52642);
INSERT INTO Cars(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO Cars(Name, Price) VALUES('Skoda', 9000);
INSERT INTO Cars(Name, Price) VALUES('Volvo', 29000);
INSERT INTO Cars(Name, Price) VALUES('Bentley', 350000);
INSERT INTO Cars(Name, Price) VALUES('Citroen', 21000);
INSERT INTO Cars(Name, Price) VALUES('Hummer', 41400);
INSERT INTO Cars(Name, Price) VALUES('Volkswagen', 21600);
这是我们从中检索数据的Cars
表。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>OpenCSVDatabaseEx</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>
</project>
Maven 构建文件包含 Opencsv 和 MySQL 驱动程序的依赖项。
OpenCSVDatabaseEx.java
package com.zetcode;
import com.opencsv.CSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class OpenCSVDatabaseEx {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb?useSsl=false";
String user = "testuser";
String password = "test623";
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (Connection con = DriverManager.getConnection(url, user, password);
PreparedStatement pst = con.prepareStatement("SELECT * FROM Cars");
ResultSet rs = pst.executeQuery()) {
try (CSVWriter writer = new CSVWriter(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8), CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END)) {
writer.writeAll(rs, true);
}
} catch (SQLException | IOException ex) {
Logger.getLogger(OpenCSVDatabaseEx.class.getName()).log(
Level.SEVERE, ex.getMessage(), ex);
}
}
}
在示例中,我们连接到 MySQL 数据库并从Cars
表中检索所有行。 数据被写入cars.csv
文件。
try (Connection con = DriverManager.getConnection(url, user, password);
PreparedStatement pst = con.prepareStatement("SELECT * FROM Cars");
ResultSet rs = pst.executeQuery()) {
我们使用驱动程序管理器连接到数据库表,并执行SELECT * FROM Cars
语句。
try (CSVWriter writer = new CSVWriter(Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8), CSVWriter.DEFAULT_SEPARATOR,
CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.NO_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END)) {
我们创建一个CSVWriter
,它带有默认的分隔符,没有引号,没有转义符和默认行尾。
writer.writeAll(rs, true);
writeAll()
方法将java.sql.ResultSet
作为参数。 第二个参数指定是否应包含字段头。
$ cat cars.csv
ID,NAME,PRICE
1,Audi,52642
2,Mercedes,57127
3,Skoda,9000
4,Volvo,29000
5,Bentley,350000
6,Citroen,21000
7,Hummer,41400
8,Volkswagen,21600
9,Toyota,26700
代码示例将生成此文件。
Opencsv 映射到 JavaBeans
CsvToBean
用于将 CSV 数据映射到 JavaBeans。
按列名映射
使用HeaderColumnNameMappingStrategy
,我们可以使用 CSV 文件第一行中的列名将 CSV 数据映射到 Java 对象
$ tree
.
├── nbactions.xml
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── bean
│ │ │ └── Car.java
│ │ └── OpenCSVReadBeansEx.java
│ └── resources
│ └── cars.csv
└── test
└── java
This is the project structure.
cars.csv
ID,NAME,PRICE
1,Audi,52642
2,Mercedes,57127
3,Skoda,9000
4,Volvo,29000
5,Bentley,350000
6,Citroen,21000
7,Hummer,41400
8,Volkswagen,21600
9,Toyota,26700
这是cars.csv
文件。 第一条记录包含列名。
Car.java
package com.zetcode.bean;
import com.opencsv.bean.CsvBindByName;
public class Car {
@CsvBindByName
private int id;
@CsvBindByName
private String name;
@CsvBindByName
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
Car
是 JavaBean。 它包含@CsvBindByName
注解,用于将 bean 属性映射到 CSV 列。
OpenCSVReadBeansEx.java
package com.zetcode;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.zetcode.bean.Car;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class OpenCSVReadBeansEx {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8)) {
HeaderColumnNameMappingStrategy<Car> strategy
= new HeaderColumnNameMappingStrategy<>();
strategy.setType(Car.class);
CsvToBean csvToBean = new CsvToBeanBuilder(br)
.withType(Car.class)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
List<Car> cars = csvToBean.parse();
cars.forEach(System.out::println);
}
}
}
该示例从cars.csv
文件中读取数据,并将它们映射到Car
对象。 它使用HeaderColumnNameMappingStrategy
。
HeaderColumnNameMappingStrategy<Car> strategy
= new HeaderColumnNameMappingStrategy<>();
strategy.setType(Car.class);
HeaderColumnNameMappingStrategy
使用 CSV 文件第一行中的列名将数据映射到对象。 列顺序无关紧要。
CsvToBean csvToBean = new CsvToBeanBuilder(br)
.withType(Car.class)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
用CsvToBeanBuilder
创建一个CsvToBean
。 我们指定类型和映射策略。
List<Car> cars = csvToBean.parse();
使用CsvToBean
的parse()
方法,我们将 CSV 数据解析到列表中。
cars.forEach(System.out::println);
我们遍历 bean 列表并将它们打印到控制台。
Car{id=1, name=Audi, price=52642}
Car{id=2, name=Mercedes, price=57127}
Car{id=3, name=Skoda, price=9000}
Car{id=4, name=Volvo, price=29000}
Car{id=5, name=Bentley, price=350000}
Car{id=6, name=Citroen, price=21000}
Car{id=7, name=Hummer, price=41400}
Car{id=8, name=Volkswagen, price=21600}
Car{id=9, name=Toyota, price=26700}
这是示例的输出。
按列位置进行映射
ColumnPositionMappingStrategy
按列的位置映射。
cars.csv
1,Audi,52642
2,Mercedes,57127
3,Skoda,9000
4,Volvo,29000
5,Bentley,350000
6,Citroen,21000
7,Hummer,41400
8,Volkswagen,21600
9,Toyota,26700
这是cars.csv
文件。
Car.java
package com.zetcode.bean;
import com.opencsv.bean.CsvBindByPosition;
public class Car {
@CsvBindByPosition(position = 0)
private int id;
@CsvBindByPosition(position = 1)
private String name;
@CsvBindByPosition(position = 2)
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
@CsvBindByPosition
指定 CSV 输入的列号和 bean 中的字段之间的绑定。
OpenCSVReadBeansEx2.java
package com.zetcode;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.zetcode.bean.Car;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class OpenCSVReadBeansEx2 {
public static void main(String[] args) throws IOException {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(myPath,
StandardCharsets.UTF_8)) {
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(Car.class);
String[] fields = {"id", "name", "price"};
strategy.setColumnMapping(fields);
CsvToBean csvToBean = new CsvToBeanBuilder(br)
.withType(Car.class)
.withMappingStrategy(strategy)
.withIgnoreLeadingWhiteSpace(true)
.build();
List<Car> cars = csvToBean.parse();
cars.forEach(System.out::println);
}
}
}
该示例从cars.csv
文件中读取数据,并将它们映射到Car
对象。 它使用ColumnPositionMappingStrategy
。
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(Car.class);
String[] fields = {"id", "name", "price"};
strategy.setColumnMapping(fields);
我们创建一个ColumnPositionMappingStrategy
。 使用setColumnMapping()
,我们设置要映射的列名。
Opencsv 使用StatefulBeanToCsv
编写 JavaBeans
在下一个示例中,我们使用StatefulBeanToCsv
将 JavaBeans 写入 CSV。
Car.java
package com.zetcode.bean;
public class Car {
private int id;
private String name;
private int price;
public Car() {
}
public Car(int id, String name, int price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Car{id=").append(id).append(", name=")
.append(name).append(", price=").append(price).append("}");
return builder.toString();
}
}
这是一个Car
bean。
OpenCSVWriteBeansEx.java
package com.zetcode;
import com.opencsv.CSVWriter;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import com.zetcode.bean.Car;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class OpenCSVWriteBeansEx {
public static void main(String[] args) {
String fileName = "src/main/resources/cars.csv";
Path myPath = Paths.get(fileName);
List<Car> cars = new ArrayList<>();
cars.add(new Car(1, "Audi", 52642));
cars.add(new Car(2, "Mercedes", 57127));
cars.add(new Car(3, "Skoda", 9000));
cars.add(new Car(4, "Volvo", 29000));
try (BufferedWriter writer = Files.newBufferedWriter(myPath,
StandardCharsets.UTF_8)) {
StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.build();
beanToCsv.write(cars);
} catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException |
IOException ex) {
Logger.getLogger(OpenCSVWriteBeansEx.class.getName()).log(
Level.SEVERE, ex.getMessage(), ex);
}
}
}
该示例创建一个汽车对象列表,并将其写入 CSV 文件。
List<Car> cars = new ArrayList<>();
cars.add(new Car(1, "Audi", 52642));
cars.add(new Car(2, "Mercedes", 57127));
cars.add(new Car(3, "Skoda", 9000));
cars.add(new Car(4, "Volvo", 29000));
我们创建汽车对象列表。
StatefulBeanToCsv<Car> beanToCsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.build();
用StatefulBeanToCsvBuilder
创建一个StatefulBeanToCsv
。
beanToCsv.write(cars);
Bean 被写入文件。
在本教程中,我们使用了 Opencsv 库。 我们已经从 CSV 文件读取数据,将数据写入 CSV 文件,从数据库表中导出数据到 CSV 文件,以及将 CSV 数据映射到 bean。
您可能也对以下相关教程感兴趣: Java 教程,读取 WAR 中的 CSV 文件,Java 文本文件读取 和 jQuery 自动完成教程。
用 Java8 的StringJoiner
连接字符串
原文:http://zetcode.com/articles/java8stringjoiner/
在本文中,我们介绍了用于连接字符串的新 Java8 API。 Java 多年来缺乏用于简单字符串连接的 API。 在 Java8 中,引入了StringJoiner
。
StringJoiner
用于构造由定界符分隔的字符序列,并可选地以提供的前缀开始并以提供的后缀结束。
StringJoiner
也由String
类的join()
方法在内部使用。
使用StringJoiner
下面的示例将数字与StringJoiner
类相连。
Java8StringJoinEx.java
package com.zetcode;
import java.util.StringJoiner;
public class Java8StringJoinEx {
public static void main(String[] args) {
StringJoiner join = new StringJoiner(",");
join.add("1");
join.add("2");
join.add("3");
join.add("4");
join.add("5");
System.out.println(join);
}
}
该示例连接了五个数字,并将最终字符串输出到控制台。
StringJoiner join = new StringJoiner(",");
将创建StringJoiner
类的新实例。 逗号字符用作分隔符。
join.add("1");
join.add("2");
join.add("3");
join.add("4");
join.add("5");
add()
方法添加了五个值。
System.out.println(join);
StringJoiner
转换为字符串并打印到控制台。
$ java com.zetcode.Java8StringJoinEx
1,2,3,4,5
这是示例的输出。
String.join()
方法
在第二个示例中,我们使用String.join()
方法连接字符串。
Java8StringJoinEx2.java
package com.zetcode;
public class Java8StringJoinEx2 {
public static void main(String[] args) {
String join = String.join("/", "2016", "8", "5");
System.out.println(join);
}
}
String.join()
方法在内部使用StringJoiner
。
String join = String.join("/", "2016", "8", "5");
日期与String.join()
方法连接在一起。
$ java com.zetcode.Java8StringJoinEx2
2016/8/5
This is the output of the example.
连接列表
第三个示例连接列表的元素。
Java8StringJoinEx3.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
public class Java8StringJoinEx3 {
public static void main(String[] args) {
List<String> list = Arrays.asList("Today", "is", "a", "beautiful", "day");
String joined = String.join(" ", list);
System.out.println(joined);
}
}
可以将列表作为参数传递给String.join()
方法。
String joined = String.join(" ", list);
列表中的元素以单个空格字符连接。
$ java com.zetcode.Java8StringJoinEx3
Today is a beautiful day
列表中的元素被连接起来以创建一个句子。
读取 CSV 文件
以下示例从 CSV 文件中读取数字,然后将其与StringJoiner
结合在一起。 我们使用 Gradle 构建工具构建示例。
$ tree
.
├── build.gradle
└── src
└── main
├── java
│ └── com
│ └── zetcode
│ └── Java8StringJoinEx4.java
└── resources
└── numbers.csv
6 directories, 3 files
该示例具有他的项目结构。 我们将要读取的数字位于resources
目录中。
build.gradle
version '1.0'
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 1.8
mainClassName = "com.zetcode.Java8StringJoinEx4"
这是 Gradle 构建文件。
numbers.csv
13,24,35,16,50
这是numbers.csv
文件。
Java8StringJoinEx4.java
package com.zetcode;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.StringJoiner;
public class Java8StringJoinEx4 {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner = new Scanner(new File("src/main/resources/numbers.csv"));
scanner.useDelimiter(",");
StringJoiner join = new StringJoiner("|");
while (scanner.hasNext()) {
join.add(scanner.next());
}
scanner.close();
System.out.println(join);
}
}
该示例读取包含数字的 CSV 文件,并使用其他定界符将它们与StringJoiner
结合在一起。
Scanner scanner = new Scanner(new File("src/main/resources/numbers.csv"));
scanner.useDelimiter(",");
使用Scanner
类读取值。 数字之间用逗号分隔,因此我们使用useDelimiter()
方法设置逗号分隔符。
StringJoiner join = new StringJoiner("|");
StringJoiner
类用"|"
定界符实例化。
while (scanner.hasNext()) {
join.add(scanner.next());
}
我们使用扫描器检索值并将其与连接器连接。
$ gradle build
:compileJava
:processResources
:classes
:jar
:startScripts
:distTar
:distZip
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
我们使用gradle build
命令构建项目。
$ gradle run
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
13|24|35|16|50
我们使用gradle run
命令运行该应用。 最后一行是我们应用的输出。
编写 CSV 文件
下一个示例将数字写入 CSV 文件。
$ tree
.
├── build.gradle
└── src
└── main
└── java
└── com
└── zetcode
└── Java8StringJoinEx5.java
该示例具有他的项目结构。 我们将在当前工作目录中创建一个新文件。
build.gradle
version '1.0'
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 1.8
mainClassName = "com.zetcode.Java8StringJoinEx5"
This is the Gradle build file.
Java8StringJoinEx5.java
package com.zetcode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.StringJoiner;
public class Java8StringJoinEx5 {
public static void main(String[] args) throws FileNotFoundException,
IOException {
StringJoiner join = new StringJoiner(",");
join.add("21");
join.add("43");
join.add("54");
join.add("76");
join.add("98");
File newFile = new File("numbers2.csv");
newFile.createNewFile();
PrintWriter pw = new PrintWriter(newFile);
pw.write(join.toString());
pw.close();
}
}
该示例将五个数字与StringJoiner
结合在一起,然后将所包含的字符串写入 CSV 文件。
StringJoiner join = new StringJoiner(",");
join.add("21");
join.add("43");
join.add("54");
join.add("76");
join.add("98");
五个数字与StringJoiner
连接在一起。 数字用逗号分隔。
File newFile = new File("numbers.csv");
newFile.createNewFile();
在当前工作目录中创建一个新的文件对象。
File newFile = new File("numbers.csv");
newFile.createNewFile();
A new file object is created in the current working directory.
PrintWriter pw = new PrintWriter(newFile);
pw.write(join.toString());
pw.close();
合并的值将写入文件。
$ gradle build run
我们构建并运行该应用。
$ cat numbers2.csv
21,43,54,76,98
我们显示创建文件的内容。
Collectors.joining()
Java8 还在新的流 API 中引入了Collectors.joining()
方法。 该方法返回一个Collector
,它按遇到顺序连接由指定定界符分隔的输入元素。
Java8CollectorJoiningEx.java
package com.zetcode;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Java8CollectorJoiningEx {
public static void main(String[] args) {
Stream<String> stream = Stream.of("Jan", "Peter", "Robert");
String names = stream.collect(Collectors.joining(" "));
System.out.println(names);
}
}
该示例使用流 API 连接三个名称。
$ java com.zetcode.Java8CollectorJoiningEx
Jan Peter Robert
This is the output of the example.
在本文中,我们使用了 Java8 中引入的新类StringJoiner
。我们还添加了一个小示例,显示了来自流 API 的新Collectors.joining()
。
您可能也对以下相关教程感兴趣: Java 教程, Java8 forEach
教程,Google Guava 简介,在 Java 中过滤列表或 Android 教程。
{% raw %}
Java 数组
原文:http://zetcode.com/lang/java/arrays/
在 Java 教程的这一部分中,我们将介绍数组。 数组是一个包含固定数量的单一类型值的容器对象。 创建数组时将确定数组的长度。 创建后,其长度是固定的。
标量变量一次只能容纳一项。 数组可以容纳多个项目。 这些项目称为数组的元素。 数组存储相同数据类型的数据。 每个元素都可以由索引引用。 数组从零开始。 第一个元素的索引为零。
Java 数组定义
数组用于存储我们应用的数据。 我们声明数组为某种数据类型。 我们指定它们的长度。 我们用数据初始化数组。 我们有几种使用数组的方法。 我们可以修改元素,对其进行排序,复制或搜索。
int[] ages;
String[] names;
float[] weights;
我们有三个数组声明。 该声明包括两部分:数组的类型和数组的名称。 数组的类型具有确定数组中元素的类型(在我们的情况下为int
,String
和float
)的数据类型,并带有一对方括号[]
。 方括号表示我们有一个数组。
集合具有类似数组的作用。 它们比数组更强大。 稍后将在单独的章节中进行介绍。
Java 初始化数组
有几种方法可以用 Java 初始化数组。 在第一个示例中,分两个步骤创建和初始化一个数组。
com/zetcode/InitArray.java
package com.zetcode;
import java.util.Arrays;
public class InitArray {
public static void main(String[] args) {
int[] a = new int[5];
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;
System.out.println(Arrays.toString(a));
}
}
我们创建并初始化一个数值数组。 数组的内容将打印到控制台。
int[] a = new int[5];
在这里,我们创建一个可以包含五个元素的数组。 该语句为五个整数分配内存。 方括号用于声明数组,类型(在我们的示例中为int
)告诉我们数组将保存哪种类型的值。 数组是一个对象,因此使用new
关键字创建它。
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;
我们用一些数据初始化数组。 这是分配初始化。 索引在方括号中。 1 号将是数组的第一个元素,2 号是第二个,依此类推。
System.out.println(Arrays.toString(a));
Arrays
类是一个帮助器类,其中包含用于操纵数组的各种方法。 toString()
方法返回指定数组内容的字符串表示形式。 此方法有助于调试。
$ java InitArray.java
[1, 2, 3, 4, 5]
这是com.zetcode.InitArray
示例的输出。
我们可以在一个语句中声明并初始化一个数组。
com/zetcode/InitArray2.java
package com.zetcode;
import java.util.Arrays;
public class InitArray2 {
public static void main(String[] args) {
int[] a = new int[] { 2, 4, 5, 6, 7, 3, 2 };
System.out.println(Arrays.toString(a));
}
}
这是先前程序的修改版本。
int[] array = new int[] { 2, 4, 5, 6, 7, 3, 2 };
一步创建并初始化一个数组。 元素在大括号中指定。 我们没有指定数组的长度。 编译器将为我们完成此任务。
通过仅指定大括号之间的数字,可以进一步简化一步创建和初始化。
com/zetcode/InitArray3.java
package com.zetcode;
import java.util.Arrays;
public class InitArray3 {
public static void main(String[] args) {
int[] a = { 2, 4, 5, 6, 7, 3, 2 };
System.out.println(Arrays.toString(a));
}
}
整数数组是使用最简单的数组创建方法创建的。
int[] a = { 2, 4, 5, 6, 7, 3, 2 };
new int[]
构造可以省略。 该语句的右侧是数组字面值表示法。 它类似于数组初始化的 C/C++ 样式。 即使我们删除new
关键字,该数组的创建方式也与前两个示例相同。 这只是一个方便的速记符号。
Java 数组访问元素
创建数组后,可以通过其索引访问其元素。 索引是放在数组名称后面方括号内的数字。
com/zetcode/AccessingElements.java
package com.zetcode;
public class AccessingElements {
public static void main(String[] args) {
String[] names = {"Jane", "Thomas", "Lucy", "David"};
System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
}
}
在示例中,我们创建一个字符串名称数组。 我们通过其索引访问每个元素,并将它们打印到终端。
String[] names = {"Jane", "Thomas", "Lucy", "David"};
将创建一个字符串数组。
System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
数组的每个元素都打印到控制台。 在names[0]
构造中,我们引用了名称数组的第一个元素。
$ java AccessingElements.java
Jane
Thomas
Lucy
David
运行示例,我们得到上面的输出。
可以更改数组的元素。 元素不是一成不变的。
com/zetcode/AccessingElements2.java
package com.zetcode;
import java.util.Arrays;
public class AccessingElements2 {
public static void main(String[] args) {
int[] vals = { 1, 2, 3 };
vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;
System.out.println(Arrays.toString(vals));
}
}
我们有一个由三个整数组成的数组。 每个值都将乘以 2。
int[] vals = { 1, 2, 3 };
创建一个由三个整数组成的数组。
vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;
使用元素访问,我们将数组中的每个值乘以 2。
$ java AccessingElements2.java
[2, 4, 6]
所有三个整数均已乘以数字 2。
Java 遍历数组
我们经常需要遍历数组的所有元素。 我们展示了两种遍历数组的常用方法。
com/zetcode/TraversingArrays.java
package com.zetcode;
public class TraversingArrays {
public static void main(String[] args) {
String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
"Saturn", "Uranus", "Neptune", "Pluto" };
for (int i=0; i < planets.length; i++) {
System.out.println(planets[i]);
}
for (String planet : planets) {
System.out.println(planet);
}
}
}
将创建一个行星名称数组。 我们使用for
循环来打印所有值。
for (int i=0; i < planets.length; i++) {
System.out.println(planets[i]);
}
在此循环中,我们利用了可以从数组对象中获取元素数量的事实。 元素数存储在length
常量中。
for (String planet : planets) {
System.out.println(planet);
}
遍历数组或其他集合时,可以使用增强的for
关键字使代码更紧凑。 在每个循环中,将行星变量传递给行星数组中的下一个值。
Java 将数组传递给方法
在下一个示例中,我们将数组传递给方法。
com/zetcode/PassingArrays.java
package com.zetcode;
import java.util.Arrays;
public class PassingArray {
public static void main(String[] args) {
int[] a = { 3, 4, 5, 6, 7 };
int[] r = reverseArray(a);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(r));
}
private static int[] reverseArray(int[] b) {
int[] c = new int[b.length];
for (int i=b.length-1, j=0; i>=0; i--, j++) {
c[j] = b[i];
}
return c;
}
}
该示例重新排列数组的元素。 为此,创建了reverseArray()
方法。
private static int[] reverseArray(int[] b) {
reverseArray()
方法将数组作为参数并返回一个数组。 该方法获取传递的数组的副本。
int[] c = new int[b.length];
在方法的主体内部,创建了一个新的数组; 它将包含新排序的元素。
for (int i=b.length-1, j=0; i>=0; i--, j++) {
c[j] = b[i];
}
在此for
循环中,我们用复制的数组的元素填充新数组。 元素是相反的。
return c;
新形成的数组将返回给调用方。
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(r));
我们打印原始数组和反转数组的元素。
$ java PassingArray.java
[3, 4, 5, 6, 7]
[7, 6, 5, 4, 3]
这是示例的输出。
Java 多维数组
到目前为止,我们一直在处理一维数组。 在 Java 中,我们可以创建多维数组。 多维数组是数组的数组。 在这样的数组中,元素本身就是数组。 在多维数组中,我们使用两组或更多组括号。
com/zetcode/TwoDimensions.java
package com.zetcode;
public class TwoDimensions {
public static void main(String[] args) {
int[][] twodim = new int[][] { {1, 2, 3}, {1, 2, 3} };
int d1 = twodim.length;
int d2 = twodim[1].length;
for (int i = 0; i < d1; i++) {
for (int j = 0; j < d2; j++) {
System.out.println(twodim[i][j]);
}
}
}
}
在此示例中,我们创建一个二维整数数组。
int[][] twodim = new int[][] { {1, 2, 3}, {1, 2, 3} };
两对方括号用于声明二维数组。 在花括号内,我们还有另外两对花括号。 它们代表两个内部数组。
int d1 = twodim.length;
int d2 = twodim[1].length;
我们确定容纳其他两个数组的外部数组和第二个内部数组的长度。
for (int i = 0; i < d1; i++) {
for (int j = 0; j < d2; j++) {
System.out.println(twodim[i][j]);
}
}
两个for
循环用于打印二维数组中的所有六个值。 twodim[i][j]
数组的第一个索引引用内部数组之一。 第二个索引引用所选内部数组的元素。
$ java TwoDimensions.java
1
2
3
1
2
3
这是程序的输出。
以类似的方式,我们创建了一个三维整数数组。
com/zetcode/ThreeDimensions.java
package com.zetcode;
public class ThreeDimensions {
public static void main(String[] args) {
int[][][] n3 = {
{{12, 2, 8}, {0, 2, 1}},
{{14, 5, 2}, {0, 5, 4}},
{{3, 26, 9}, {8, 7, 1}},
{{4, 11, 2}, {0, 9, 6}}
};
int d1 = n3.length;
int d2 = n3[0].length;
int d3 = n3[0][0].length;
for (int i = 0; i < d1; i++) {
for (int j = 0; j < d2; j++) {
for (int k = 0; k < d3; k++) {
System.out.print(n3[i][j][k] + " ");
}
}
}
System.out.print('\n');
}
}
拥有三维数组的变量用三对方括号声明。 这些值放在三对大括号内。
int[][][] n3 = {
{{12, 2, 8}, {0, 2, 1}},
{{14, 5, 2}, {0, 5, 4}},
{{3, 26, 9}, {8, 7, 1}},
{{4, 11, 2}, {0, 9, 6}}
};
创建三维数组n3
。 它是一个具有元素的数组,这些元素本身就是数组的数组。
int d1 = n3.length;
int d2 = n3[0].length;
int d3 = n3[0][0].length;
我们得到所有三个维度的长度。
for (int i = 0; i < d1; i++) {
for (int j = 0; j < d2; j++) {
for (int k = 0; k < d3; k++) {
System.out.print(n3[i][j][k] + " ");
}
}
}
我们需要三个for
循环来遍历三维数组。
$ java ThreeDimensions.java
12 2 8 0 2 1 14 5 2 0 5 4 3 26 9 8 7 1 4 11 2 0 9 6
我们将三维数组的内容打印到控制台。
Java 不规则数组
元素大小相同的数组称为矩形数组。 可以创建数组大小不同的不规则数组。 在 C# 中,此类数组称为锯齿状数组。
com/zetcode/IrregularArrays.java
package com.zetcode;
public class IrregularArrays {
public static void main(String[] args) {
int[][] ir = new int[][] {
{1, 2},
{1, 2, 3},
{1, 2, 3, 4}
};
for (int[] a : ir) {
for (int e : a) {
System.out.print(e + " ");
}
}
System.out.print('\n');
}
}
这是不规则数组的示例。
int[][] ir = new int[][] {
{1, 2},
{1, 2, 3},
{1, 2, 3, 4}
};
这是不规则数组的声明和初始化。 三个内部数组具有 2、3 和 4 个元素。
for (int[] a : ir) {
for (int e : a) {
System.out.print(e + " ");
}
}
增强的for
循环用于遍历数组的所有元素。
$ java IrregularArrays.java
1 2 1 2 3 1 2 3 4
This is the output of the example.
Java 数组方法
java.util
包中提供的Arrays
类是一个帮助器类,其中包含使用数组的方法。 这些方法可用于修改,排序,复制或搜索数据。 我们使用的这些方法是Array
类的静态方法。 (静态方法是可以在不创建类实例的情况下调用的方法。)
com/zetcode/ArrayMethods.java
package com.zetcode;
import java.util.Arrays;
public class ArrayMethods {
public static void main(String[] args) {
int[] a = {5, 2, 4, 3, 1};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
Arrays.fill(a, 8);
System.out.println(Arrays.toString(a));
int[] b = Arrays.copyOf(a, 5);
if (Arrays.equals(a, b)) {
System.out.println("Arrays a, b are equal");
} else {
System.out.println("Arrays a, b are not equal");
}
}
}
在代码示例中,我们将介绍Arrays
类的五个方法。
import java.util.Arrays;
我们将对Arrays
类使用简写形式。
int[] a = {5, 2, 4, 3, 1};
我们有五个整数的数组。
Arrays.sort(a);
sort()
方法按升序对整数进行排序。
System.out.println(Arrays.toString(a));
toString()
方法返回指定数组内容的字符串表示形式。
Arrays.fill(a, 8);
fill()
方法将指定的整数值分配给数组的每个元素。
int[] b = Arrays.copyOf(a, 5);
copyOf()
方法将指定数量的元素复制到新数组。
if (Arrays.equals(a, b)) {
System.out.println("Arrays a, b are equal");
} else {
System.out.println("Arrays a, b are not equal");
}
equals()
方法比较两个数组。 如果两个数组包含相同顺序的相同元素,则它们相等。
$ java ArrayMethods.java
[1, 2, 3, 4, 5]
[8, 8, 8, 8, 8]
Arrays a, b are equal
这是输出。
Java 比较数组
比较数组有两种方法。 equals()
方法和deepEquals()
方法。 deepEquals()
方法也将引用与数组内部的数组进行比较。
com/zetcode/ComparingArrays.java
package com.zetcode;
import java.util.Arrays;
public class ComparingArrays {
public static void main(String[] args) {
int[] a = {1, 1, 2, 1, 1};
int[] b = {0, 0, 3, 0, 0};
int[][] c = {
{1, 1, 2, 1, 1},
{0, 0, 3, 0, 0}
};
int[][] d = {
a,
b
};
System.out.print("equals() method: ");
if (Arrays.equals(c, d)) {
System.out.println("Arrays c, d are equal");
} else {
System.out.println("Arrays c, d are not equal");
}
System.out.print("deepEquals() method: ");
if (Arrays.deepEquals(c, d)) {
System.out.println("Arrays c, d are equal");
} else {
System.out.println("Arrays c, d are not equal");
}
}
}
该示例说明了两种方法之间的区别。
int[] a = {1, 1, 2, 1, 1};
int[] b = {0, 0, 3, 0, 0};
我们有两个整数数组。
int[][] c = {
{1, 1, 2, 1, 1},
{0, 0, 3, 0, 0}
};
c
数组有两个内部数组。 内部数组的元素等于a
和b
数组。
int[][] d = {
a,
b
};
d
数组包含对a
和b
数组的引用。
System.out.print("equals() method: ");
if (Arrays.equals(c, d)) {
System.out.println("Arrays c, d are equal");
} else {
System.out.println("Arrays c, d are not equal");
}
System.out.print("deepEquals() method: ");
if (Arrays.deepEquals(c, d)) {
System.out.println("Arrays c, d are equal");
} else {
System.out.println("Arrays c, d are not equal");
}
现在,使用这两种方法比较c
和d
数组。 对于equals()
方法,数组不相等。 deepEquals()
方法在引用数组中更深入,并检索它们的元素以进行比较。 对于此方法,c
和d
数组相等。
$ java ComparingArrays.java
equals() method: Arrays c, d are not equal
deepEquals() method: Arrays c, d are equal
这是示例输出。
Java 搜索数组
Arrays
类具有一种用于搜索数组中元素的简单方法。 它称为binarySearch()
。 该方法使用二进制搜索算法搜索元素。 binarySearch()
方法仅适用于排序数组。
com/zetcode/Searching.java
package com.zetcode;
import java.util.Arrays;
public class Searching {
public static void main(String[] args) {
String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter",
"Saturn", "Uranus", "Neptune", "Pluto" };
Arrays.sort(planets);
String p = "Earth";
int r = Arrays.binarySearch(planets, p);
String msg;
if (r >= 0) {
msg = String.format("%s was found at position %d of the "
+ "sorted array", p, r);
} else {
msg = p + " was not found";
}
System.out.println(msg);
}
}
在该示例中,我们在一系列行星中搜索"Earth"
字符串。
Arrays.sort(planets);
由于该算法仅适用于排序后的数组,因此我们必须首先对数组进行排序。
String p = "Earth";
我们将搜索"Earth"
元素。
int r = Arrays.binarySearch(planets, p);
调用binarySearch()
方法。 第一个参数是数组名称,第二个参数是我们要查找的元素。 如果找到该元素,则返回值大于或等于零。 在这种情况下,它是排序数组中元素的索引。
if (r >= 0) {
msg = String.format("%s was found at position %d of the "
+ "sorted array", p, r);
} else {
msg = p + " was not found";
}
根据返回的值,我们创建一条消息。
$ java Searching.java
Earth was found at position 0 of the sorted array
This is the example output.
下载图片
在下一个示例中,我们显示如何下载图像。
com/zetcode/DownloadImage.java
package com.zetcode;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
public class DownloadImage {
public static void main(String[] args) throws IOException {
var imageUrl = "http://webcode.me/favicon.ico";
var destinationFile = "favicon.ico";
var url = new URL(imageUrl);
try (var is = url.openStream();
var fos = new FileOutputStream(destinationFile)) {
byte[] buf = new byte[1024];
int noOfBytes;
while ((noOfBytes = is.read(buf)) != -1) {
fos.write(buf, 0, noOfBytes);
}
}
}
}
该示例下载一个小的favicon.ico
图像。
byte[] buf = new byte[1024];
图像是字节数组。 我们创建一个byte
值的空数组,其大小足以容纳该图标。
while ((noOfBytes = is.read(buf)) != -1) {
fos.write(buf, 0, noOfBytes);
}
我们读取二进制数据并将其写入文件。
在 Java 教程的这一部分中,我们使用了数组。 我们已经描述了如何初始化数组,访问数组元素,遍历数组,使用多维数组,比较数组以及搜索数组元素。
{% endraw %}
Java 中元素迭代的历史
原文:http://zetcode.com/articles/javaiterationhistory/
在本教程中,我们将研究 Java 中元素迭代的历史。
编程中最常见的任务之一就是迭代数据集合。 本教程说明了随着时间的推移,元素迭代如何随 Java 语言一起发展。
Enumeration
在 Java 的早期,Enumeration
用于迭代数据元素。 Enumeration
接口定义了一些方法,我们可以通过这些方法枚举(一次获得一个元素)对象集合中的元素。 两个主要的集合类是Vector
和Hashtable
。
今天,Enumeration
,Vector
和Hashtable
被认为已过时。 但是,它们不被弃用。
EnumerationEx.java
package com.zetcode;
import java.util.Enumeration;
import java.util.Vector;
public class EnumerationEx {
public static void main(String[] args) {
Vector items = new Vector();
items.add("coin");
items.add("pen");
items.add("chair");
items.add("lamp");
items.add("cup");
items.add("spoon");
Enumeration itemsEn = items.elements();
while (itemsEn.hasMoreElements()) {
System.out.println(itemsEn.nextElement());
}
}
}
我们有一个向量字符串。 我们使用Enumeration
遍历向量的元素。
Enumeration itemsEn = items.elements();
elements()
方法返回向量的Enumeration
。
while (itemsEn.hasMoreElements()) {
System.out.println(itemsEn.nextElement());
}
元素在while
循环中遍历。 当还有更多元素要提取时,hasMoreElements()
返回true
,而在列举所有元素时返回false
。
迭代器
Java 1.2 引入了标准集合类(List
,Set
,Map
)和Iterator
。 Iterator
带来了迭代器设计模式,这是一种常见的行为模式,用于按顺序访问集合对象的元素,而无需了解其基础表示。
IteratorEx.java
package com.zetcode;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class IteratorEx {
public static void main(String[] args) {
List<String> items = Arrays.asList("coin", "ball", "lamp", "spoon");
Iterator it = items.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
在示例中,我们使用Iterator
遍历元素列表。
List<String> items = Arrays.asList("coin", "ball", "lamp", "spoon");
我们使用Arrays.asList()
方法在一行中定义一个列表。
Iterator it = items.iterator();
我们使用iterator()
方法从列表中获得迭代器。
while (it.hasNext()) {
System.out.println(it.next());
}
我们在while
循环中浏览元素列表。 我们使用迭代器的hasNext()
和next()
方法。
可迭代对象和增强的for
循环
Java 5 引入了泛型Iterable
和增强的for
循环。 Iterable
接口允许对象成为增强的for
循环语句的目标。 Iterable
是一个对象,其中包含可以迭代的一系列元素。 它具有一种产生Iterator
的方法。
EnhancedForLoop.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
public class EnhancedForLoop {
public static void main(String[] args) {
List<String> items = Arrays.asList("coin", "ball", "lamp", "spoon");
for (String item: items) {
System.out.println(item);
}
}
}
该示例使用增强的for
循环遍历列表元素。 迭代器的创建以及对hasNext()
和next()
方法的调用不是明确的,但它们仍在幕后进行。
Java8 forEach()
方法
forEach()
方法对Iterable
的每个元素执行给定的操作,直到所有元素都已处理或该操作引发异常。 forEach()
方法使用内部迭代器,而先前的方法使用外部迭代器。
ForEachEx.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
public class ForEachEx {
public static void main(String[] args) {
List<String> items = Arrays.asList("coin", "ball", "lamp", "spoon");
items.forEach(System.out::println);
}
}
在示例中,我们使用forEach()
方法遍历元素。
在本教程中,我们研究了 Java 中元素迭代的简要历史。
您可能也对以下相关教程感兴趣:用 Java 过滤列表, Java ArrayList
教程, Opencsv 教程, Java 教程,用 Java 读取文本 或用 Java 读取网页或 Google Guava 简介。
Java 谓词
原文:http://zetcode.com/java/predicate/
Java 谓词教程展示了如何在 Java 中使用谓词。 使用谓词,我们可以创建更清晰易读的代码。 谓词还有助于创建更好的测试。
谓词
谓词的一般含义是对正确或错误的陈述。 在编程中,谓词表示返回布尔值的单个参数函数。
Java 谓词
Java 中的谓词通过接口实现。 Predicate<T>
是表示单个参数函数的通用函数接口,该函数返回布尔值。 它位于java.util.function
包中。 它包含test(T t)
方法,该方法求值给定参数上的谓词。
在 Java 中,我们没有独立的函数。 此外,方法不是一等公民。 (不能将它们添加到集合中或作为参数传递给方法。)因此,我们定义接口并从这些接口创建对象。 然后可以将此类对象传递给Iterables.filter()
之类的方法。 使用 Java lambda,使用谓词要容易得多。
Java 谓词示例
以下示例创建一个简单的 Java 谓词。
com/zetcode/JavaPredicateEx.java
package com.zetcode;
import java.util.List;
import java.util.function.Predicate;
class BiggerThanFive<E> implements Predicate<Integer> {
@Override
public boolean test(Integer v) {
Integer five = 5;
return v > five;
}
}
public class JavaPredicateEx {
public static void main(String[] args) {
List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);
BiggerThanFive<Integer> btf = new BiggerThanFive<>();
nums.stream().filter(btf).forEach(System.out::println);
}
}
在示例中,谓词用于过滤整数。
class BiggerThanFive<E> implements Predicate<Integer> {
@Override
public boolean test(Integer v) {
Integer five = 5;
return v > five;
}
}
这是实现Predicate<Integer>
接口的 Java 类。 对于大于 5 的值,其test()
方法返回 true。
List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);
我们有一个整数值列表。
BiggerThanFive<Integer> btf = new BiggerThanFive<>();
实例化了BiggerThanFive
。
nums.stream().filter(btf).forEach(System.out::println);
谓词对象将传递给filter()
方法,以从列表中获取所有大于 5 的值。
6
7
8
9
12
这是输出。
使用 lambda 和谓词
Java lambda 表达式简化了 Java 谓词的创建。
com/zetcode/JavaPredicateEx2.java
package com.zetcode;
import java.util.List;
import java.util.function.Predicate;
public class JavaPredicateEx2 {
public static void main(String[] args) {
List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);
Predicate<Integer> btf = n -> n > 5;
nums.stream().filter(btf).forEach(System.out::println);
}
}
该示例过滤整数值; 这次我们使用 Java lambda 表达式,这使代码更短。
Predicate<Integer> btf = n -> n > 5;
这是创建谓词的单一语言。
Java 谓词示例 II
下一个示例使用具有两个条件的谓词。
com/zetcode/Country.java
package com.zetcode;
public class Country {
private String name;
private int population;
public Country(String name, int population) {
this.name = name;
this.population = population;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public String toString() {
return "Country{" + "name=" + name +
", population=" + population + '}';
}
}
我们有一个Country
类; 它具有name
和population
属性。
com/zetcode/JavaPredicateEx3.java
package com.zetcode;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class JavaPredicateEx3 {
public static void main(String[] args) {
List<Country> countries = new ArrayList<>();
countries.add(new Country("Iran", 80840713));
countries.add(new Country("Hungary", 9845000));
countries.add(new Country("Poland", 38485000));
countries.add(new Country("India", 1342512000));
countries.add(new Country("Latvia", 1978000));
countries.add(new Country("Vietnam", 95261000));
countries.add(new Country("Sweden", 9967000));
countries.add(new Country("Iceland", 337600));
countries.add(new Country("Israel", 8622000));
Predicate<Country> p1 = c -> c.getName().startsWith("I") &&
c.getPopulation() > 10000000;
countries.stream().filter(p1).forEach(System.out::println);
}
}
在示例中,我们创建了一个国家列表。 我们按国家名称和人口过滤列表。
Predicate<Country> p1 = c -> c.getName().startsWith("I") &&
c.getPopulation() > 10000000;
对于以"I"
开头且人口超过一千万的国家,该谓词返回正确。
Country{name=Iran, population=80840713}
Country{name=India, population=1342512000}
名单中有两个国家满足条件:伊朗和印度。
Java IntPredicate
IntPredicate
表示一个int
值自变量的谓词。 这是Predicate<E>
的int
消耗型原始类型特化。
com/zetcode/IntPredicateEx.java
package com.zetcode;
import java.util.Arrays;
import java.util.function.IntPredicate;
public class IntPredicateEx {
public static void main(String[] args) {
int[] nums = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };
IntPredicate p = n -> n > 5;
Arrays.stream(nums).filter(p).forEach(System.out::println);
}
}
该示例使用filter()
和IntPredicate
过滤int
值数组。
int nums[] = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };
我们定义一个整数数组。
IntPredicate p = n -> n > 5;
创建了IntPredicate
; 如果int
值大于 5,则返回true
。
Arrays.stream(nums).filter(p).forEach(System.out::println);
我们从数组创建一个流并过滤元素。 filter()
方法接收谓词作为参数。
组合谓词
使用and()
和or()
方法,我们可以用 Java 编写谓词。
com/zetcode/JavaPredicateCompose.java
package com.zetcode;
import java.util.Arrays;
import java.util.function.IntPredicate;
public class JavaPredicateCompose {
public static void main(String[] args) {
int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};
IntPredicate p1 = n -> n > 3;
IntPredicate p2 = n -> n < 9;
Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);
System.out.println("**********");
IntPredicate p3 = n -> n == 6;
IntPredicate p4 = n -> n == 9;
Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);
}
}
该示例使用IntPredicates
的组成过滤数据。
IntPredicate p1 = n -> n > 3;
IntPredicate p2 = n -> n < 9;
Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);
我们将两个谓词与and()
方法结合使用; 我们得到大于 3 且小于 9 的整数。
IntPredicate p3 = n -> n == 6;
IntPredicate p4 = n -> n == 9;
Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);
使用or()
方法,我们得到的值等于 6 或 9。
5
6
7
8
**********
6
9
这是输出。
否定谓词
negate()
方法返回一个谓词,该谓词表示给定谓词的逻辑非。
com/zetcode/JavaPredicateNegate.java
package com.zetcode;
import java.util.Arrays;
import java.util.function.IntPredicate;
public class JavaPredicateNegate {
public static void main(String[] args) {
int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};
IntPredicate p = n -> n > 5;
Arrays.stream(nums).filter(p).forEach(System.out::println);
System.out.println("**********");
Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);
}
}
该示例演示了negate()
方法的用法。
IntPredicate p = n -> n > 5;
我们有一个谓词,对于大于 5 的值返回true
。
Arrays.stream(nums).filter(p).forEach(System.out::println);
我们过滤所有大于 5 的整数。
Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);
使用negate()
方法,我们得到相反的结果:值小于或等于 4。
6
7
8
9
12
**********
2
3
1
5
这是示例的输出。
Java 谓词作为方法参数
谓词可以作为方法参数传递。
com/zetcode/PredicateMethodParam.java
package com.zetcode;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PredicateMethodParam {
public static void main(String args[]) {
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12);
List<Integer> all = eval(list, n -> true);
System.out.println(all);
List<Integer> evenValues = eval(list, n -> n % 2 == 0);
System.out.println(evenValues);
List<Integer> greaterThanSix = eval(list, n -> n > 6);
System.out.println(greaterThanSix);
}
private static List<Integer> eval(List<Integer> values,
Predicate<Integer> predicate) {
return values.stream().filter(predicate)
.collect(Collectors.toList());
}
}
在示例中,我们将谓词函数作为第二个参数传递给eval()
方法。
在本教程中,我们使用了 Java 谓词。 您可能也对相关教程感兴趣: Java 教程, Java 中的HashMap
迭代, Java ArrayList
教程, Java HashSet
教程, Java static
关键字, Java8 forEach
教程,读取 Java 中的文本文件和读取和写入 Java 中的 ICO 图像。
列出所有 Java 教程。
Java StringBuilder
原文:http://zetcode.com/java/stringbuilder/
Java StringBuilder
教程显示了如何在 Java 中使用StringBuilder
。 Java String
对象是不可变的。 只能创建原始字符串的修饰副本。 当我们需要就地修改字符串时,可以使用StringBuilder
。
StringBuilder
StringBuilder
是可变的字符序列。 当我们想就地修改 Java 字符串时,使用StringBuilder
。 StringBuffer
是类似于StringBuilder
的线程安全等效项。
StringBuilder
具有允许修改字符串的方法,例如append()
,insert()
或replace()
。
Java StringBuilder
构造器
StringBuilder
具有四个构造器:
构造器 | 描述 |
---|---|
StringBuilder() |
创建一个初始容量为 16 个字符的空字符串构建器 |
StringBuilder(CharSequence seq) |
从CharSequence 创建一个字符串生成器 |
StringBuilder(int capcity) |
用指定的首字母创建一个空的字符串生成器 |
StringBuilder(String str) |
从指定的字符串创建字符串生成器 |
Java StringBuilder
是可变的
Java String
是不可变的,而StringBuilder
是可变的。
MutableImmutableEx.java
package com.zetcode;
public class MutableImmutableEx {
public static void main(String[] args) {
var word = "rock";
var word2 = word.replace('r', 'd');
System.out.println(word2);
var builder = new StringBuilder("rock");
builder.replace(0, 1, "d");
System.out.println(builder);
}
}
该示例演示了String
和StringBuilder
之间的主要区别。
var word2 = word.replace('r', 'd');
Java String
具有replace()
方法,但它不会修改原始字符串。 而是创建修改后的副本。
var builder = new StringBuilder("rock");
builder.replace(0, 1, "d");
另一方面,StringBuilder
替换字符串。
dock
dock
这是输出。
Java StringBuilder
附加方法
StringBuilder
包含几个重载append()
方法,它们在字符串的末尾添加一个值。
StringBuilderEx.java
package com.zetcode;
import java.util.stream.LongStream;
public class StringBuilderAppendEx {
private final static long MAX_VAL = 500;
public static void main(String[] args) {
var builder = new StringBuilder();
var sum = LongStream.rangeClosed(0, MAX_VAL).sum();
LongStream.rangeClosed(1, MAX_VAL).forEach(e -> {
builder.append(e);
if (e % 10 == 0) {
builder.append("\n");
}
if (e < MAX_VAL) {
builder.append(" + ");
} else {
builder.append(" = ");
}
});
builder.append(sum);
System.out.println(builder);
}
}
该示例从数百个小字符串中构建一个大字符串。 字符串的格式如下:1 + 2 + 3 + ... + MAX_VAL = SUM
。
var builder = new StringBuilder();
空的StringBuilder
被创建。
LongStream.rangeClosed(1, MAX_VAL).forEach(e -> {
将创建一个值范围1..MAX_VAL
。 我们使用forEach()
方法迭代这些值。
builder.append(e);
我们使用append()
方法将当前值附加到字符串生成器。
if (e % 10 == 0) {
builder.append("\n");
}
为了使输出适合屏幕,我们在每十个值之后添加一个换行符。
if (e < MAX_VAL) {
builder.append(" + ");
} else {
builder.append(" = ");
}
在这些值之间,我们添加+
或"="
字符。
builder.append(sum);
在字符串的末尾,我们添加值的总和。
System.out.println(builder);
最后,字符串被打印到控制台。
StringBuilder
插入方法
insert()
方法用于将字符串插入构建器的指定位置。
StringBuilderInsertEx.java
package com.zetcode;
public class StringBuilderInsertEx {
public static void main(String[] args) {
var sentence = "There is a red fox in the forest.";
var builder = new StringBuilder(sentence);
builder.insert(19, "and a wolf ");
System.out.println(builder);
}
}
该示例使用insert()
方法将字符串插入句子中。
There is a red fox and a wolf in the forest.
我们创建了这句话。
获取子字符串的索引
indexOf()
方法返回第一次出现的子字符串,而lastIndexOf()
方法返回最后出现的子字符串。
StringBuilderIndexesEx.java
package com.zetcode;
public class StringBuilderIndexesEx {
public static void main(String[] args) {
var builder = new StringBuilder();
builder.append("There is a wolf in the forest. ");
builder.append("The wolf appeared very old. ");
builder.append("I never saw a wild wolf in my life.");
var term = "wolf";
int firstIdx = builder.indexOf(term);
int firstIdx2 = builder.indexOf(term, 15);
System.out.format("First occurrence of %s %d%n", term, firstIdx);
System.out.format("First occurrence of %s %d%n", term, firstIdx2);
int lastIdx = builder.lastIndexOf(term);
int lastIdx2 = builder.lastIndexOf(term, 15);
System.out.format("Last occurrence of %s %d%n", term, lastIdx);
System.out.format("Last occurrence of %s %d%n", term, lastIdx2);
System.out.println(builder);
}
}
该示例使用indexOf()
和lastIndexOf()
方法来获取"wolf"
子字符串的索引。
var builder = new StringBuilder();
builder.append("There is a wolf in the forest. ");
builder.append("The wolf appeared very old. ");
builder.append("I never saw a wild wolf in my life.");
我们使用append()
方法创建一个字符串生成器。
int firstIdx = builder.indexOf(term);
我们从生成器中首次获得"wolf"
一词。
int firstIdx2 = builder.indexOf(term, 15);
从索引 15 开始,我们从构建器中首次获得"wolf"
术语。
int lastIdx = builder.lastIndexOf(term);
int lastIdx2 = builder.lastIndexOf(term, 15);
同样,我们获得"wolf"
子字符串的最后一次出现。
First occurrence of wolf 11
First occurrence of wolf 35
Last occurrence of wolf 78
Last occurrence of wolf 11
There is a wolf in the forest. The wolf appeared very old. I never saw
a wild wolf in my life.
这是输出。
StringBuilder
替换方法
replace()
方法用指定的新字符串替换字符串生成器中的子字符串。
StringBuilderReplaceEx.java
package com.zetcode;
public class StringBuilderReplaceEx {
public static void main(String[] args) {
var sentence = "I saw a red fox running into the forest.";
var builder = new StringBuilder(sentence);
var term = "fox";
var newterm = "dog";
int idx = builder.indexOf(term);
int len = term.length();
builder.replace(idx, idx + len, newterm);
System.out.println(builder);
}
}
该示例将"fox"
子字符串替换为"dog"
字符串。
int idx = builder.indexOf(term);
我们找到要替换的子字符串的开始索引。
int len = term.length();
在我们的操作中,我们需要知道子字符串的长度。
builder.replace(idx, idx + len, newterm);
我们称为replace()
方法。 第一个参数是要删除的子字符串的开始索引,第二个参数是要删除的子字符串的结束索引。 第三个参数是新字符串。
StringBuilder
删除字符
在字符串构建器中,有两种删除字符的方法。
StringBuilderRemoveEx.java
package com.zetcode;
public class StringBuilderRemoveEx {
public static void main(String[] args) {
var sentence = "There is a red fox in the forest.";
var builder = new StringBuilder(sentence);
builder.delete(11, 14);
System.out.println(builder);
builder.deleteCharAt(11);
System.out.println(builder);
}
}
该示例从字符串中删除一些字符。
builder.delete(11, 14);
使用delete()
方法,我们删除了由索引指定的子字符串。
builder.deleteCharAt(11);
使用delete()
方法,我们删除一个字符; 在我们的情况下,它是多余的空格字符。
There is a fox in the forest.
There is a fox in the forest.
这是输出。
StringBuilder
子字符串
使用substring()
方法可以从字符串返回子字符串。
StringBuilderSubstringsEx.java
package com.zetcode;
public class StringBuilderSubstringsEx {
public static void main(String[] args) {
var sentence = "There is a red fox in the forest.";
var builder = new StringBuilder(sentence);
var word = builder.substring(15, 18);
System.out.println(word);
var sbstr = builder.substring(15);
System.out.println(sbstr);
}
}
在示例中,我们检索了两个子字符串。
var word = builder.substring(15, 18);
该行检索起始索引为 15 且终止索引为 18 的子字符串。
var sbstr = builder.substring(15);
在这里,我们检索从索引 15 到句子结尾的子字符串。
fox
fox in the forest.
这是输出。
在本教程中,我们使用了 Java StringBuilder
。 您可能也对相关教程感兴趣: Java 教程, Java 拆分字符串教程, Java 中的HashMap
迭代, Java ArrayList
教程 , Java HashSet
教程, Java NumberFormat
教程, Java8 forEach
教程,读取 Java 文本文件和用 Java 读取和编写 ICO 图像。
Java 分割字串教学
原文:http://zetcode.com/java/splitstring
Java 拆分字符串教程展示了如何在 Java 中拆分字符串。 我们使用String
的split()
,Pattern
的splitAsStream()
和 Guava Splitter
的on()
方法。
String
具有用于拆分字符串的内置方法:
String[]
split(String regex)
- 将字符串拆分为给定正则表达式的匹配项String[]
split(String regex, int limit)
- 在给定正则表达式的匹配项附近拆分此字符串
该方法返回一个拆分字符串数组。
除了split()
方法外,Pattern
也具有splitAsStream()
方法。
分割电话号码
在第一个示例中,我们拆分了一个电话号码。
StringSplitEx.java
package com.zetcode;
import java.util.Arrays;
public class StringSplitEx {
public static void main(String[] args) {
var phoneNumber = "202-555-0154";
String[] output = phoneNumber.split("-");
Arrays.stream(output).forEach(part -> System.out.println(part));
}
}
电话号码通常用破折号(-)分隔。 程序使用split()
将数字拆分为数值。
var phoneNumber = "202-555-0154";
这是电话号码。
String[] output = phoneNumber.split("-");
我们用破折号将字符串分开; split()
方法返回从主字符串分割的子字符串数组。
Arrays.stream(output).forEach(part -> System.out.println(part));
我们向控制台显示拆分的部分。
202
555
0154
这是输出。
用点字符分割字符串
点字符在正则表达式语法中具有特殊含义。 要用点分隔字符串,我们需要对其进行转义或使用Pattern.quote()
。
StringSplitDotEx
package com.zetcode;
import java.util.Arrays;
import java.util.regex.Pattern;
public class StringSplitDotEx {
public static void main(String[] args) {
var address = "127.0.0.1";
// String[] output = address.split("\\.");
String[] output = address.split(Pattern.quote("."));
Arrays.stream(output).forEach(part -> System.out.println(part));
}
}
该程序将拆分 IP 地址。
限制分割字符串
limit
选项控制拆分子字符串的数量。
SplitStringLimitEx.java
package com.zetcode;
import java.util.Arrays;
public class SplitStringLimitEx {
public static void main(String[] args) {
var names = "Jane-Paul-Ferenc-David-Robert-Julia";
var output = names.split("-", 4);
Arrays.stream(output).forEach(System.out::println);
}
}
该程序将names
字符串分为四个部分。
Jane
Paul
Ferenc
David-Robert-Julia
这是输出。
分割和修剪字符串
我们通常需要删除字符串周围的空格字符。
SplitStringTrimEx.java
package com.zetcode;
import java.util.Arrays;
public class SplitStringTrimEx {
public static void main(String[] args) {
var input = " wood, falcon\t, sky, forest\n";
var output = input.trim().split("\\s*,\\s*");
Arrays.stream(output).forEach(System.out::println);
}
}
要删除空白,我们使用trim()
。
var output = input.trim().split("\\s*,\\s*");
正则表达式用逗号分隔输入字符串,逗号前后可能有任意多个空格。
用模式串分割字符串
我们可以使用流使用函数式的方式使用Pattern
分割字符串。
PatternCompileEx.java
package com.zetcode;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class PatternCompileEx {
public static void main(String[] args) {
var phoneNumber = "202-555-0154";
var output = Pattern.compile("-")
.splitAsStream(phoneNumber)
.collect(Collectors.toList());
output.forEach(System.out::println);
}
}
该示例使用Pattern
的splitAsStream()
方法拆分电话号码。
var output = Pattern.compile("-")
.splitAsStream(phoneNumber)
.collect(Collectors.toList());
我们编译包含用于分割的字符的正则表达式。 在编译的表达式上,我们调用splitAsStream()
以获取拆分子字符串流。 最后,我们将流收集到一个列表中。
用 Guava 的拆分器拆分字符串
以下示例使用 Google 的 Guava 库拆分字符串。 它使用Splitter
类。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
我们需要包括 Guava 的依赖项。
SplitStringGuavaEx.java
package com.zetcode;
import com.google.common.base.Splitter;
public class SplitStringGuavaEx {
public static void main(String[] args) {
var input = " falcon, \t\tforest\t, \t\t, moderate, sky\n";
var result = Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.splitToList(input);
result.forEach(System.out::println);
}
}
程序使用 Guava 的Splitter
分割字符串。
var result = Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.splitToList(input);
我们使用Splitter.on()
从输入字符串中提取不重叠的子字符串。 trimResults()
删除空格字符,omitEmptyStrings()
删除潜在的空字符串。 结果将转换为列表。
在本教程中,我们展示了如何在 Java 中分割字符串。 您可能也对相关教程感兴趣: Java 文件教程, Java fibonacci 教程, Java 创建目录,用 Java 复制文件 , Java Unix 时间,用 Java 创建文件, Java StringBuilder
教程和 Java 教程。
Java NumberFormat
原文:http://zetcode.com/java/numberformat/
Java NumberFormat 教程显示了如何使用 Java 格式化数字。 不同的文化使用不同的方式表示数字。 例如,货币格式化的方式在世界各国中有很大不同。
NumberFormat
NumberFormat
是用于格式化和解析数字的 Java 类。 使用NumberFormat
,我们可以格式化和解析任何语言环境的数字。
NumberFormat
允许我们根据特定的语言环境舍入值,设置小数点分隔符,设置小数位数或格式化值。
创建 Java NumberFormat
NumberFormat
有几种创建数字格式的静态方法。
static NumberFormat getInstance(Locale inLocale)
此getInstance()
方法返回指定语言环境的通用数字格式。
NumberFormat
格式化数字
不同地区的数字格式不同。 例如,某些国家/地区使用点作为小数点分隔符(美国,英国),而其他国家/地区则使用逗号(斯洛伐克,法国)。
FormattingNumbers.java
package com.zetcode;
import java.text.NumberFormat;
import java.util.Locale;
public class FormattingNumbers {
public static void main(String[] args) {
double n = 1240.35;
NumberFormat nf = NumberFormat.getInstance(new Locale("en", "US"));
String val = nf.format(n);
System.out.println(val);
NumberFormat nf2 = NumberFormat.getInstance(new Locale("sk", "SK"));
String val2 = nf2.format(n);
System.out.println(val2);
NumberFormat nf3 = NumberFormat.getInstance(new Locale("da", "DK"));
String val3 = nf3.format(n);
System.out.println(val3);
}
}
该示例在三个不同的语言环境中显示一个数字。
double n = 1240.35;
这是要格式化的值。
NumberFormat nf = NumberFormat.getInstance(new Locale("en", "US"));
我们为美国语言环境创建一个NumberFormat
。
String val = nf.format(n);
我们使用format()
方法格式化该值。
NumberFormat nf2 = NumberFormat.getInstance(new Locale("sk", "SK"));
String val2 = nf2.format(n);
在这里,我们格式化斯洛伐克语区域设置的值。
1,240.35
1 240,35
1.240,35
美国,斯洛伐克和丹麦对数字分组和小数点使用不同的字符。
NumberFormat
分组数字
为了便于阅读,可以使用定界符将具有许多数字的数字分为几组。 setGroupingUsed()
设置是否以格式使用分组。
Grouping.java
package com.zetcode;
import java.text.NumberFormat;
import java.util.Locale;
public class Grouping {
public static void main(String[] args) {
long val = 23_500_390_800_380L;
NumberFormat nf = NumberFormat.getInstance(new Locale("sk", "SK"));
nf.setGroupingUsed(true);
System.out.println(nf.format(val));
nf.setGroupingUsed(false);
System.out.println(nf.format(val));
}
}
我们有很多电话。 我们演示了斯洛伐克语言环境的数字分组。
long val = 23_500_390_800_380L;
从 Java 7 开始,可以在数字字面值中使用下划线字符。
nf.setGroupingUsed(true);
我们使用setGroupingUsed()
方法设置分组。
23 500 390 800 380
23500390800380
第一个值比第二个更具可读性。 斯洛伐克使用空格字符进行数字分组。
NumberFormat
小数位数
我们可以用setMinimumFractionDigits()
和setMaximumFractionDigits()
控制小数位数。 如果位数少于最小小数位数,则将零添加到该值。 如果位数比小数位数的最大位数多,则四舍五入。
FractionDigits.java
package com.zetcode;
import java.text.NumberFormat;
import java.util.Locale;
public class FractionDigits {
public static void main(String[] args) {
double val1 = 4.5678934;
double val2 = 2.3;
NumberFormat nf = NumberFormat.getInstance(new Locale("sk", "SK"));
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(4);
System.out.println(nf.format(val1));
System.out.println(nf.format(val2));
}
}
在示例中,我们设置了分数位数的最小和最大数目。
4,5679
2,30
第一个值四舍五入,第二个值再加上一个零数字。
NumberFormat
舍入数字
如前所述,如果小数位数多于允许位数的最大值,则该值将四舍五入。 有几种可用的舍入技术。
RoundingNumbers.java
package com.zetcode;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;
public class RoundingNumbers {
public static void main(String[] args) {
double nums[] = {2.32, 2.55, 3.19, 4.88, 5.54, 3.22, 8.78};
NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
nf.setMaximumFractionDigits(1);
nf.setRoundingMode(RoundingMode.UP);
for (double num : nums) {
String number = nf.format(num);
System.out.printf("%s ", number);
}
System.out.println();
nf.setRoundingMode(RoundingMode.DOWN);
for (double num : nums) {
String number = nf.format(num);
System.out.printf("%s ", number);
}
System.out.println();
}
}
该示例使用以下两种舍入模式对双数进行舍入:RoundingMode.UP
和RoundingMode.DOWN
。
nf.setMaximumFractionDigits(1);
nf.setRoundingMode(RoundingMode.UP);
我们通过setMaximumFractionDigits()
设置最大小数位数,并通过setRoundingMode()
设置舍入模式。
2.4 2.6 3.2 4.9 5.6 3.3 8.8
2.3 2.5 3.1 4.8 5.5 3.2 8.7
这是输出。
NumberFormat
格式化百分比
NumberFormat.getPercentInstance()
用于格式化百分比。
Percentages.java
package com.zetcode;
import java.text.NumberFormat;
import java.util.Locale;
public class Percentages {
public static void main(String[] args) {
double x = 25f / 100f;
NumberFormat pf = NumberFormat.getPercentInstance(new Locale("sk", "SK"));
System.out.println(pf.format(x));
}
}
该示例将双精度值格式化为百分比。
25%
这是输出。
NumberFormat
格式货币
处理数字时最复杂的任务之一是格式化货币。 我们使用NumberFormat.getCurrencyInstance()
来获取货币的数字格式。
Currencies.java
package com.zetcode;
import java.text.NumberFormat;
import java.util.Locale;
public class Currencies {
public static void main(String[] args) {
int val = 23_500;
NumberFormat cf1 = NumberFormat.getCurrencyInstance(new Locale("en", "US"));
System.out.println(cf1.format(val));
NumberFormat cf2 = NumberFormat.getCurrencyInstance(new Locale("sk", "SK"));
System.out.println(cf2.format(val));
NumberFormat cf3 = NumberFormat.getCurrencyInstance(new Locale("zh", "CN"));
System.out.println(cf3.format(val));
}
}
该示例显示三个不同国家/地区的货币:美国,斯洛伐克和中国。
NumberFormat cf3 = NumberFormat.getCurrencyInstance(new Locale("zh", "CN"));
此行获取人民币的数字格式。
$23,500.00
23 500,00 €
¥23,500.00
这是输出。
NumberFormat
解析数字
parse()
方法从给定字符串的开头解析文本以产生数字。
ParsingNumbers.java
package com.zetcode;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class ParsingNumbers {
public static void main(String[] args) throws ParseException {
NumberFormat nf = NumberFormat.getInstance(new Locale("sk", "SK"));
nf.setMaximumFractionDigits(3);
Number num = nf.parse("150000,456");
System.out.println(num.doubleValue());
}
}
该示例使用斯洛伐克语语言环境解析值。
在本教程中,我们使用 Java NumberFormat
。 我们设置了数字,货币,百分比,四舍五入的格式,设置了小数位数,并设置了数字分组。
您可能也对相关教程感兴趣: Java 教程, Java StringBuilder
教程, Java ArrayList
教程, Java static
关键字, Java8 forEach
教程,读取 Java 中的文本文件和用 Java 读取和写入 ICO 图像。
Java TemporalAdjusters
教程
原文:http://zetcode.com/java/temporaladjusters/
Java TemporalAdjusters
教程展示了如何使用TemporalAdjusters
修改 Java 中的Temporal
对象。
时间是日期,时间和偏移对象的基本接口类型,包括LocalDate
,LocalTime
,LocalDateTime
和Instant
。
Java TemporalAdjusters
TemporalAdjusters
用于修改时间对象。 他们允许查找星期,月份或年份的第一天或最后一天; 一周的第二天或下一天,依此类推。
Java TemporalAdjusters
示例
以下示例使用内置的TemporalAdjusters
方法。
JavaTemporalAdjustersEx.java
package com.zetcode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class JavaTemporalAdjustersEx {
public static void main(String[] args) {
var localDate = LocalDate.now();
System.out.printf("today: %s%n", localDate);
var date1 = localDate.with(TemporalAdjusters.firstDayOfMonth());
System.out.printf("first day of month: %s%n", date1);
var date2 = localDate.with(TemporalAdjusters.lastDayOfMonth());
System.out.printf("last day of month: %s%n", date2);
var date3 = localDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.printf("next Monday: %s%n", date3);
var date4 = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.printf("first day of next month: %s%n", date4);
var date5 = localDate.with(TemporalAdjusters.lastDayOfYear());
System.out.printf("last day of year: %s%n", date5);
var date6 = localDate.with(TemporalAdjusters.firstDayOfYear());
System.out.printf("first day of year: %s%n", date6);
var date7 = localDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
System.out.printf("last Sunday of month: %s%n", date7);
}
}
该示例介绍了七个时间调节器。
var localDate = LocalDate.now();
我们使用LocalDate.now()
计算当前本地日期。
var date1 = localDate.with(TemporalAdjusters.firstDayOfMonth());
使用firstDayOfMonth()
,我们可以找到当月的第一天。
var date2 = localDate.with(TemporalAdjusters.lastDayOfMonth());
使用lastDayOfMonth()
,我们可以找到该月的最后一天。
var date3 = localDate.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
使用next()
和DayOfWeek.MONDAY
,我们找到下一个星期一。
var date4 = localDate.with(TemporalAdjusters.firstDayOfNextMonth());
使用firstDayOfNextMonth()
,我们可以找到下个月的第一天。
var date5 = localDate.with(TemporalAdjusters.lastDayOfYear());
使用lastDayOfYear()
,我们可以找到一年中的最后一天。
var date6 = localDate.with(TemporalAdjusters.firstDayOfYear());
使用firstDayOfYear()
,可以找到一年的第一天。
var date7 = localDate.with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
使用lastInMonth()
和DayOfWeek.SUNDAY
,我们可以找到该月的最后一个星期日。
today: 2018-12-03
first day of month: 2018-12-01
last day of month: 2018-12-31
next monday: 2018-12-10
first day of next month: 2019-01-01
last day of year: 2018-12-31
first day of year: 2018-01-01
last Sunday of month: 2018-12-30
这是输出。
Java 自定义TemporalAdjuster
我们可以创建我们的自定义时间调整器。
JavaCustomTemporalAdjusterEx.java
package com.zetcode;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.TemporalAdjuster;
public class JavaCustomTemporalAdjusterEx {
public static void main(String[] args) {
var localDate = LocalDate.of(2018, 12, 3);
TemporalAdjuster taj = t -> t.plus(Period.ofDays(14));
var result = localDate.with(taj);
System.out.printf("Adding 14 days to %s gives %s",
localDate, result);
}
}
本示例使用LocalDate.of()
创建日期。 它在日期上增加了 14 天并打印结果。
TemporalAdjuster taj = t -> t.plus(Period.ofDays(14));
这是一个 lambda 表达式,它创建一个TemporalAdjuster
,它向创建的日期对象增加 14 天。
var result = localDate.with(taj);
我们得到结果。
Adding 14 days to 2018-12-03 gives 2018-12-17
这是输出。
我们可以通过实现TemporalAdjuster
接口来创建时间调整器。
JavaCustomTemporalAdjusterEx2.java
package com.zetcode;
import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
class NextChristmas implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ChronoField.MONTH_OF_YEAR, 12)
.with(ChronoField.DAY_OF_MONTH, 25);
}
}
public class JavaCustomTemporalAdjusterEx2 {
public static void main(String[] args) {
var now = LocalDate.now();
System.out.println("Today: " + now);
var xmas = now.with(new NextChristmas());
System.out.println("Next XMas: " + xmas);
}
}
在示例中,自定义TemporalAdjuster
计算下一个 XMas 的日期。
@Override
public Temporal adjustInto(Temporal temporal) {
return temporal.with(ChronoField.MONTH_OF_YEAR, 12)
.with(ChronoField.DAY_OF_MONTH, 25);
}
我们实现了adjustInto()
方法,该方法返回 XMa 的Temporal
对象,调用该方法的日期应调整为该对象。
Today: 2018-12-03
Next XMas: 2018-12-25
这是输出。
在本教程中,我们使用 Java TemporalAdjusters
完成了日期和时间的修改。
您可能对以下相关教程感兴趣: Java 文件教程, Java LocalTime
教程, Java 教程和 Java Unix 时间教程。
Apache FileUtils
教程
原文:http://zetcode.com/java/fileutils/
Apache FileUtils
教程显示了如何使用 Apache FileUtils
来处理 Java 中的文件和目录。 这些示例读取,写入,复制,创建,删除,列出文件并获取文件大小。
Apache FileUtils
是常规的文件操作工具。 FileUtils
是 Apache Commons IO 的一部分,Apache Commons IO 是一个工具库,可帮助开发 Java 中的 IO 功能。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
在示例中,我们使用commons-io
依赖项。
Apache FileUtils
创建和删除文件
使用FileUtils.touch()
创建一个新文件,并使用FileUtils.deleteQuietly()
将其删除。
CreateDeleteFileEx.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
public class CreateDeleteFileEx {
public static void main(String[] args) throws IOException {
File myfile = new File("src/main/resources/myfile.txt");
FileUtils.touch(myfile);
if (myfile.exists()) {
System.out.println("The file exists");
} else {
System.out.println("The file does not exist");
}
FileUtils.deleteQuietly(myfile);
if (myfile.exists()) {
System.out.println("The file exists");
} else {
System.out.println("The file does not exist");
}
}
}
该示例创建一个新文件,检查其存在,将其删除,然后再次检查其存在。
File myfile = new File("src/main/resources/myfile.txt");
FileUtils.touch(myfile);
使用FileUtils.touch()
创建一个新文件。
if (myfile.exists()) {
我们使用File
的exists()
方法检查文件是否存在。
FileUtils.deleteQuietly(myfile);
该文件用FileUtils.deleteQuietly()
删除。
Apache FileUtils
复制文件
可以使用FileUtils.copyFile()
和FileUtils.copyFileToDirectory()
方法复制文件。 要比较文件内容,我们可以使用FileUtils.contentEquals()
方法。
CopyFileEx.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
public class CopyFileEx {
public static void main(String[] args) throws IOException {
File myfile1 = new File("src/main/resources/myfile.txt");
File myfile2 = new File("src/main/resources/myfile2.txt");
FileUtils.copyFile(myfile1, myfile2);
if (FileUtils.contentEquals(myfile1, myfile2)) {
System.out.println("The files have equal content");
} else {
System.out.println("The files do not have equal content");
}
File docs = new File("src/main/resources/docs");
FileUtils.forceMkdir(docs);
FileUtils.copyFileToDirectory(myfile2, docs);
}
}
该示例将文件复制到同一目录中并比较它们的内容。 然后,它创建一个新目录并将文件复制到该新目录。
FileUtils.copyFile(myfile1, myfile2);
我们使用FileUtils.copyFile()
将文件复制到同一目录中。
if (FileUtils.contentEquals(myfile1, myfile2)) {
我们用FileUtils.contentEquals()
比较两个文件的内容。
FileUtils.forceMkdir(docs);
使用FileUtils.forceMkdir()
创建一个新目录。
FileUtils.copyFileToDirectory(myfile2, docs);
使用FileUtils.copyFileToDirectory()
将文件复制到新目录。
在下面的示例中,我们将 URL 资源复制到本地文件。
CopyUrl2FileEx.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
public class CopyUrl2FileEx {
public static void main(String[] args) throws IOException {
URL myurl = new URL("http://www.something.com");
File myfile = new File("src/main/resources/something.html");
FileUtils.copyURLToFile(myurl, myfile);
String content = FileUtils.readFileToString(myfile,
StandardCharsets.UTF_8.name());
System.out.println(content);
}
}
该示例复制 HTML 页面并将其写入文件。
URL myurl = new URL("http://www.something.com");
我们阅读了www.something.com
网页的内容。
File myfile = new File("src/main/resources/something.html");
页面的 HTML 内容将被写入src/main/resources/something.html
文件。
FileUtils.copyURLToFile(myurl, myfile);
我们使用FileUtils.copyURLToFile()
将网页复制到本地文件。
String content = FileUtils.readFileToString(myfile,
StandardCharsets.UTF_8.name());
System.out.println(content);
我们读取本地文件的内容并将其打印到控制台。
Apache FileUtils
获取文件大小
我们使用FileUtils.sizeOf()
确定文件大小,并使用FileUtils.sizeOfDirectory()
确定目录大小。
GetFileSizeEx.java
package com.zetcode;
import java.io.File;
import org.apache.commons.io.FileUtils;
public class GetFileSizeEx {
public static void main(String[] args) {
File myfile = new File("/home/janbodnar/tmp/rotunda.jpg");
long fileSizeB = FileUtils.sizeOf(myfile);
System.out.printf("The size of file is: %d bytes\n", fileSizeB);
File mydir = new File("/home/janbodnar/tmp");
long dirSizeB = FileUtils.sizeOfDirectory(mydir);
double dirSizeKB = (double) dirSizeB / FileUtils.ONE_KB;
double dirSizeMB = (double) dirSizeB / FileUtils.ONE_MB;
System.out.printf("The size of directory is: %d bytes\n", dirSizeB);
System.out.printf("The size of file is: %.2f kilobytes\n", dirSizeKB);
System.out.printf("The size of file is: %.2f megabytes\n", dirSizeMB);
}
}
在示例中,我们获得文件和目录的大小。
double dirSizeKB = (double) dirSizeB / FileUtils.ONE_KB;
double dirSizeMB = (double) dirSizeB / FileUtils.ONE_MB;
我们使用FileUtils.ONE_KB
和FileUtils.ONE_MB
常数来计算大小(以千字节和兆字节为单位)。
Apache FileUtils
读取文件
可以使用FileUtils.readFileToString()
将文件读取为字符串,或者使用FileUtils.readLines()
将文件读取为字符串集合。
words.txt
blue, tank, robot, planet, wisdom, cherry,
chair, pen, keyboard, tree, forest, plant
sky, movie, white, colour, music, dog, cat
我们在src/main/resources
目录中有此文本文件。
ReadFileEx.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.commons.io.FileUtils;
public class ReadFileEx {
public static void main(String[] args) throws IOException {
File myfile = new File("src/main/resources/words.txt");
String contents = FileUtils.readFileToString(myfile,
StandardCharsets.UTF_8.name());
System.out.println(contents);
List<String> lines = FileUtils.readLines(myfile,
StandardCharsets.UTF_8.name());
System.out.printf("There are %d lines in the file\n", lines.size());
System.err.printf("The second line is: %s", lines.get(1));
}
}
该示例将文本文件读入字符串和字符串列表。
String contents = FileUtils.readFileToString(myfile,
StandardCharsets.UTF_8.name());
在FileUtils.readFileToString()
方法的第二个参数中,我们指定文件编码类型。
Apache FileUtils
写入文件
使用FileUtils.writeStringToFile()
将字符串写入文件,使用FileUtils.writeLines()
将字符串写入字符串集合。
WriteFileEx.java
package com.zetcode;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
public class WriteFileEx {
public static void main(String[] args) throws IOException {
String string = "Today is a gloomy day.";
File myfile = new File("src/main/resources/myfile.txt");
FileUtils.writeStringToFile(myfile, string,
StandardCharsets.UTF_8.name());
List<String> lines = new ArrayList<>();
lines.add("A dark forest.");
lines.add("A stray dog.");
lines.add("A massive mountain.");
File myfile2 = new File("src/main/resources/myfile2.txt");
FileUtils.writeLines(myfile2,
StandardCharsets.UTF_8.name(), lines);
}
}
该示例将一个字符串和一个字符串列表写入文件。
Apache FileUtils
列出文件
FileUtils.listFiles()
方法根据选择的条件查找文件。
ListFilesEx.java
package com.zetcode;
import java.io.File;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
public class ListFilesEx {
public static void main(String[] args) {
File myDir = new File("/home/janbodnar/tmp");
Collection<File> files = FileUtils.listFiles(myDir,
new String[] {"txt", "html"}, true);
files.stream().forEach(System.out::println);
}
}
在此示例中,我们使用FileUtils.listFiles()
查找与txt
或html
扩展名匹配的文件。
Collection<File> files = FileUtils.listFiles(myDir,
new String[] {"txt", "html"}, true);
第二个参数是扩展数组。 该文件必须与要选择的这些扩展名之一匹配。 第三个参数指定我们也在子目录中搜索文件。
下一个示例搜索与过滤器匹配的文件。
ListFilesFilterEx.java
package com.zetcode;
import java.io.File;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
public class ListFilesFilterEx {
public static void main(String[] args) {
File myDir = new File("/home/janbodnar/tmp");
Collection<File> files = FileUtils.listFiles(myDir,
new WildcardFileFilter("*.txt", IOCase.SENSITIVE),
new NotFileFilter(DirectoryFileFilter.DIRECTORY));
files.stream().forEach(System.out::println);
}
}
使用覆盖的FileUtils.listFiles()
方法,我们搜索与通配符过滤器匹配的文件。
Collection<File> files = FileUtils.listFiles(myDir,
new WildcardFileFilter("*.txt", IOCase.SENSITIVE),
new NotFileFilter(DirectoryFileFilter.DIRECTORY));
该方法的第一个参数是要搜索的目录名称。第二个参数是文件过滤器,最后一个是目录过滤器。 我们使用WildcardFileFilter
搜索与*.txt
通配符匹配的文件,并禁用NotFileFilter
搜索目录。
Apache FileUtils
获取目录
FileUtils.getTempDirectoryPath()
返回到系统临时目录的路径,FileUtils.getUserDirectoryPath()
返回到用户的主目录的路径。
GetDirsEx.java
package com.zetcode;
import org.apache.commons.io.FileUtils;
public class GetDirsEx {
public static void main(String[] args) {
String tempDir = FileUtils.getTempDirectoryPath();
System.out.println(tempDir);
String userDir = FileUtils.getUserDirectoryPath();
System.out.println(userDir);
}
}
该示例检索并打印系统临时目录和用户目录。
在本教程中,我们使用 Apache FileUtils
处理文件。 您可能也对相关教程感兴趣:用 Java 创建文件,用 Java 复制文件, Java 文件大小,用 Java 读取文本文件 ,用 Java 读写 ICO 图像, Java Swing 教程, Java 教程,用 Java 显示图像。
Java 流过滤器
原文:http://zetcode.com/java/streamfilter/
Java 流过滤器教程展示了如何使用过滤操作过滤 Java 流。
Java 流
Java 流是来自源的支持聚合操作的一系列元素。 流不存储元素。 元素是按需计算的。 元素是从数据源(如集合,数组或 I/O 资源)中消耗的。
流聚合操作类似于 SQL 操作。 我们可以对流应用过滤,映射,缩小,匹配,搜索或排序操作。 流允许链接多个流操作。 与使用外部迭代的集合不同,流在内部进行迭代。
Java 流过滤器
Java 流过滤器方法是一个中间操作,它返回与给定谓词匹配的流元素。 谓词是一个返回布尔值的函数。
Java 流过滤器字符串长度
下面的示例过滤字符串列表。
JavaStreamFilterStringLength.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStreamFilterStringLength {
public static void main(String[] args) {
List<String> words = Arrays.asList("pen", "custom", "orphanage",
"forest", "bubble", "butterfly");
List<String> result = words.stream().filter(word -> word.length() > 5)
.collect(Collectors.toList());
result.forEach(word -> System.out.println(word));
}
}
我们有一个单词表。 我们过滤列表以仅包括长度大于 5 的字符串。
List<String> result = words.stream().filter(word -> word.length() > 5)
.collect(Collectors.toList());
使用stream()
方法,我们从字符串列表创建 Java 流。 在此流上,我们应用filter()
方法。 filter()
方法接受匿名函数,该函数对长度大于 5 的流的所有元素返回布尔值true
。 我们使用collect()
方法从流中创建一个列表。
result.forEach(word -> System.out.println(word));
我们使用forEach()
方法遍历结果并将其所有元素打印到控制台。
custom
orphanage
forest
bubble
butterfly
这些单词有五个以上的字符。
Java 流过滤器空值
下一个示例过滤掉null
值。
JavaStreamFilterRemoveNulls.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStreamFilterRemoveNulls {
public static void main(String[] args) {
List<String> words = Arrays.asList("cup", null, "forest",
"sky", "book", null, "theatre");
List<String> result = words.stream().filter(w -> w != null)
.collect(Collectors.toList());
System.out.println(result);
}
}
我们有一个单词表。 通过流过滤操作,我们创建了一个新列表,其中删除了null
值。
List<String> result = words.stream().filter(w -> w != null)
.collect(Collectors.toList());
在 lambda 表达式的主体中,我们检查值是否不是null
。 collect()
方法是一种终端操作,可从过滤后的流中创建列表。
[cup, forest, sky, book, theatre]
最终输出中没有null
值。
Java 流多个过滤器操作
可以对流应用多个过滤器操作。
JavaStreamMultipleFilters.java
package com.zetcode;
import java.util.Arrays;
import java.util.function.IntConsumer;
public class JavaStreamMultipleFilters {
public static void main(String[] args) {
int[] inums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
IntConsumer icons = i -> System.out.print(i + " ");
Arrays.stream(inums).filter(e -> e < 6 || e > 10)
.filter(e -> e % 2 == 0).forEach(icons);
}
}
在示例中,我们对整数流应用了多个过滤操作。
int[] inums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
我们有一个整数值数组。
IntConsumer icons = i -> System.out.print(i + " ");
IntConsumer
是一个接受单个整数值参数且不返回结果的操作。
Arrays.stream(inums).filter(e -> e < 6 || e > 10)
.filter(e -> e % 2 == 0).forEach(icons);
使用Arrays.stream()
方法从数组创建流。 执行多个过滤操作。
2 4 12 14
这些整数满足所有过滤条件。
Java 流过滤器对象
下一个示例显示了如何过滤对象。
User.java
package com.zetcode;
public class User {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
在示例中,我们使用此User
类。
JavaStreamFilterObjects.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStreamFilterObjects {
public static void main(String[] args) {
List<User> persons = Arrays.asList(
new User("Jack", "jack234@gmail.com"),
new User("Peter", "pete2@post.com"),
new User("Lucy", "lucy17@gmail.com"),
new User("Robert", "bob56@post.com"),
new User("Martin", "mato4@imail.com")
);
List<User> result = persons.stream()
.filter(person -> person.getEmail().matches(".*post\\.com"))
.collect(Collectors.toList());
result.forEach(p -> System.out.println(p.getName()));
}
}
该示例创建User
对象的流。 它过滤与特定正则表达式匹配的那些。
List<User> result = persons.stream()
.filter(person -> person.getEmail().matches(".*post\\.com"))
.collect(Collectors.toList());
在过滤谓词中,我们选择与.*post\\.com
模式匹配的电子邮件。
Peter
Robert
这两个用户的电子邮件与常规模式匹配。
Java 流过滤器按键映射
在以下示例中,我们通过映射的键过滤映射。
JavaStreamFilterMapByValues.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class JavaStreamFilterMapByKeys {
public static void main(String[] args) {
Map<String, String> hmap = new HashMap<>();
hmap.put("de", "Germany");
hmap.put("hu", "Hungary");
hmap.put("sk", "Slovakia");
hmap.put("si", "Slovenia");
hmap.put("so", "Somalia");
hmap.put("us", "United States");
hmap.put("ru", "Russia");
hmap.entrySet().stream().filter(map -> map.getKey().startsWith("s"))
.forEach(m -> System.out.println(m));
}
}
该示例过滤以s
字母开头的域名。
si=Slovenia
sk=Slovakia
so=Somalia
这是示例的输出。
Java 流过滤器按值映射
在以下示例中,我们根据映射的值过滤映射。
JavaStreamFilterMapByValues.java
package com.zetcode;
import java.util.HashMap;
import java.util.Map;
public class JavaStreamFilterMapByValues {
public static void main(String[] args) {
Map<String, String> hmap = new HashMap<>();
hmap.put("de", "Germany");
hmap.put("hu", "Hungary");
hmap.put("sk", "Slovakia");
hmap.put("si", "Slovenia");
hmap.put("so", "Somalia");
hmap.put("us", "United States");
hmap.put("ru", "Russia");
hmap.entrySet().stream().filter(map -> map.getValue().equals("Slovakia")
|| map.getValue().equals("Slovenia"))
.forEach(m -> System.out.println(m));
}
}
在示例中,我们从映射中过滤出两个国家。
si=Slovenia
sk=Slovakia
这是输出。
在本教程中,我们已经处理过 Java 流过滤操作。 您可能也对相关教程感兴趣: Java 流,Java 流归约,Java 流映射,Java8 forEach
教程,和用 Java 过滤列表。
Java 流归约
原文:http://zetcode.com/java/streamreduce/
Java 流归约教程展示了如何对 Java8 流执行缩减操作。
Java 流
Java 流是来自源的支持聚合操作的一系列元素。 流不存储元素。 元素是按需计算的。 元素是从数据源(如集合,数组或 I/O 资源)中消耗的。
Java 流归约
归约是将流聚合为类或原始类型的终端操作。 Java8 流 API 包含一组预定义的归约操作,例如average()
,sum()
,min()
,max()
和count()
,它们通过组合流的元素来返回一个值。
Java 流reduce
方法
Stream.reduce()
是用于生成自定义归约运算的通用方法。
Optional<T> reduce(BinaryOperator<T> accumulator)
此方法使用关联累加函数对该流的元素进行归约。 它返回一个Optional
描述归约的值(如果有)。
T reduce(T identity, BinaryOperator<T> accumulator)
此方法采用两个参数:标识和累加器。 如果流中没有元素,则身份元素既是reduce
的初始值,也是默认结果。 累加器函数具有两个参数:约简的部分结果和流的下一个元素。 它返回一个新的部分结果。 Stream.reduce()
方法返回归约的结果。
Java 流内置归约
以下示例使用了两个预定义的归约操作。
JavaReduceEx.java
package com.zetcode;
import java.util.Arrays;
public class JavaReduceEx {
public static void main(String[] args) {
int vals[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
int sum = Arrays.stream(vals).sum();
System.out.printf("The sum of values: %d%n", sum);
long n = Arrays.stream(vals).count();
System.out.printf("The number of values: %d%n", n);
}
}
我们有一个整数数组。 我们使用Arrays.stream()
从数组创建一个流,并执行两个归约:sum()
和count()
。
The sum of values: 72
The number of values: 8
这是输出。
Java reduce
和Optional
具有一个参数的reduce()
方法返回Optional
,这是用于null
安全的 Java 类。
Car.java
package com.zetcode;
public class Car {
private final String name;
private final int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
public int getPrice() {
return price;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Car{name=").append(name).append(", price=")
.append(price).append("}");
return builder.toString();
}
}
这是Car
类。
JavaReduceEx2.java
package com.zetcode;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class JavaReduceEx2 {
public static void main(String[] args) {
List<Car> persons = Arrays.asList(new Car("Skoda", 18544),
new Car("Volvo", 22344),
new Car("Fiat", 23650),
new Car("Renault", 19700));
Optional<Car> car = persons.stream().reduce((c1, c2)
-> c1.getPrice() > c2.getPrice() ? c1 : c2);
car.ifPresent(System.out::println);
}
}
该示例创建一个汽车对象列表。 我们计算出最昂贵的汽车。
Optional<Car> car = persons.stream().reduce((c1, c2)
-> c1.getPrice() > c2.getPrice() ? c1 : c2);
从列表中,我们创建一个流; reduce()
方法的累加器会比较汽车的价格并返回价格较高的汽车。
car.ifPresent(System.out::println);
如果返回的归约值不为 null,则将其打印到控制台。
Car{name=Fiat, price=23650}
这是输出。
下一个示例添加了其他用例。
MyUtil.java
package com.zetcode;
public class MyUtil {
public static int add2Ints(int num1, int num2) {
return num1 + num2;
}
}
这是MyUtil
类,具有一种将两个整数相加的方法。
JavaReduceEx3.java
package com.zetcode;
import java.util.stream.IntStream;
public class JavaReduceEx3 {
public static void main(String[] args) {
IntStream.range(1, 10).reduce((x, y) -> x + y)
.ifPresent(s -> System.out.println(s));
IntStream.range(1, 10).reduce(Integer::sum)
.ifPresent(s -> System.out.println(s));
IntStream.range(1, 10).reduce(MyUtil::add2Ints)
.ifPresent(s -> System.out.println(s));
}
}
我们创建三个不同的累加器函数来计算1..10
值的总和。
IntStream.range(1, 10).reduce((x, y) -> x + y).ifPresent(s -> System.out.println(s));
在第一种情况下,我们使用 lambda 表达式进行加法。
IntStream.range(1, 10).reduce(Integer::sum).ifPresent(s -> System.out.println(s));
第二种情况使用内置的Integer::sum
方法。
IntStream.range(1, 10).reduce(MyUtil::add2Ints).ifPresent(s -> System.out.println(s));
最后,我们有一个自定义的添加方法。
Java 归约标识
正如我们已经提到的,如果流中没有元素,则标识既是还原的初始值,又是默认结果。
User.java
package com.zetcode;
import java.time.LocalDate;
import java.time.chrono.IsoChronology;
public class User {
private String name;
private LocalDate dateOfBirth;
public User(String name, LocalDate dateOfBirth) {
this.name = name;
this.dateOfBirth = dateOfBirth;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(LocalDate dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public int getAge() {
return dateOfBirth.until(IsoChronology.INSTANCE.dateNow())
.getYears();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("User{name=").append(name).append(", dateOfBirth=")
.append(dateOfBirth).append("}");
return builder.toString();
}
}
这是User
类。 除了常用的属性,获取器和设置器之外,我们还有getAge()
方法,该方法使用 Java8 日期 API 返回用户的年龄。
JavaReduceEx4.java
package com.zetcode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class JavaReduceEx4 {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User("Frank", LocalDate.of(1979, 11, 23)));
users.add(new User("Peter", LocalDate.of(1985, 1, 18)));
users.add(new User("Lucy", LocalDate.of(2002, 5, 14)));
users.add(new User("Albert", LocalDate.of(1996, 8, 30)));
users.add(new User("Frank", LocalDate.of(1967, 10, 6)));
int maxAge = users.stream().mapToInt(User::getAge)
.reduce(0, (a1, a2) -> a1 > a2 ? a1 : a2);
System.out.printf("The oldest user's age: %s%n", maxAge);
}
}
在示例中,我们创建了一个用户列表。 该示例计算最老用户的年龄。
int maxAge = users.stream().mapToInt(User::getAge)
.reduce(0, (a1, a2) -> a1 > a2 ? a1 : a2);
从列表中,我们创建一个 Java8 流。 使用mapToInt()
方法将流映射到IntStream
。 最后,reduce()
方法提供一个标识值(0)和一个累加器; 累加器将比较年龄值并返回较大的值。
在本教程中,我们已经使用 Java 流归约操作。 您可能也对相关教程感兴趣: Java 流, Java 流映射, Java 流过滤器和 Java8 forEach
教程。
Java 流映射
原文:http://zetcode.com/java/streammap/
Java 流映射教程显示了如何在 Java 流上执行映射操作。
Java 流
Java 流是来自源的支持聚合操作的一系列元素。 流不存储元素。 元素是按需计算的。 元素是从数据源(如集合,数组或 I/O 资源)中消耗的。
流聚合操作类似于 SQL 操作。 我们可以对流应用过滤,映射,缩小,匹配,搜索或排序操作。 流允许链接多个流操作。 与使用外部迭代的集合不同,流在内部进行迭代。
Java 流映射
我们可以将流元素更改为新的流; 原始来源未修改。 map()
方法返回一个流,该流由将给定功能应用于流的元素的结果组成。 map()
是一个中间操作。
Java 流映射示例
在第一个示例中,我们将算术运算映射到值列表上。
JavaStreamMapEx.java
package com.zetcode;
import java.util.Arrays;
import java.util.stream.IntStream;
public class JavaStreamMapEx {
public static void main(String[] args) {
var nums = IntStream.of(1, 2, 3, 4, 5, 6, 7, 8);
var squares = nums.map(e -> e * e).toArray();
System.out.println(Arrays.toString(squares));
}
}
在示例中,我们创建了一个整数流。 使用map()
方法,我们对这些值进行算术运算,然后将它们转换为数组。
[1, 4, 9, 16, 25, 36, 49, 64]
这是输出。
Java 流映射示例 II
在下面的示例中,我们在一个流中使用map()
和mapToInt()
方法。
JavaStreamMapEx2.java
package com.zetcode;
import java.util.Random;
import java.util.stream.Stream;
public class JavaStreamMapEx2 {
public static void main(String[] args) {
Stream.generate(new Random()::nextDouble)
.map(e -> (e * 100))
.mapToInt(Double::intValue)
.limit(5)
.forEach(System.out::println);
}
}
该示例生成五个随机 double 值。 使用映射方法,将每个随机生成的值乘以 100 并转换为整数。
66
25
18
35
47
这是一个示例输出。
Java 流映射示例 III
在下一个示例中,我们将自定义方法映射到字符串流上。
JavaStreamMapEx3.java
package com.zetcode;
import java.util.stream.Stream;
public class JavaStreamMapEx3 {
public static void main(String[] args) {
var words = Stream.of("cardinal", "pen", "coin", "globe");
words.map(JavaStreamMapEx3::capitalize).forEach(System.out::println);
}
private static String capitalize(String word) {
word = word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
return word;
}
}
该示例将流中的每个单词大写。
Cardinal
Pen
Coin
Globe
这是输出。
Java 流映射示例 IV
在下一个示例中,我们使用map
方法将 CSV 文件中的值读取到列表中。
src/resources/numbers.csv
2,3,5,6,1,0
9,5,6,3,2,1
在numbers.csv
文件中有这些值。
JavaStreamMapEx4.java
package com.zetcode;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
public class JavaStreamMapEx4 {
public static void main(String[] args) throws IOException {
var lines = Files.readAllLines(Path.of("src/resources/numbers.csv"));
var vals = lines.stream().map(line-> Arrays.asList(line.split(",")))
.flatMap(Collection::stream).mapToInt(Integer::valueOf)
.boxed().collect(Collectors.toList());
System.out.println(vals);
}
}
首先,我们将 CSV 文件读入字符串列表。 然后,我们从列表中创建一个流,并应用映射方法以最后获得一个整数列表。
var lines = Files.readAllLines(Path.of("src/resources/numbers.csv"));
使用Files.readAllLines()
,我们将文件的所有行读入字符串列表。
var vals = lines.stream().map(line-> Arrays.asList(line.split(",")))
.flatMap(Collection::stream).mapToInt(Integer::valueOf)
.boxed().collect(Collectors.toList());
我们从列表中创建一个流,将字符串拆分为字符串编号列表。 列表被展平,转换为整数并收集到最终列表中。
[2, 3, 5, 6, 1, 0, 9, 5, 6, 3, 2, 1]
这是输出。
Java 流映射示例 V
在下一个示例中,我们对用户对象列表使用map
操作。
User.java
package com.zetcode;
public class User {
private String name;
private String occupation;
public User(String name, String occupation) {
this.name = name;
this.occupation = occupation;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOccupation() {
return occupation;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
}
这是User
类。
JavaStreamMapEx5.java
package com.zetcode;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class JavaStreamMapEx5 {
public static void main(String[] args) {
var users = List.of(new User("Peter", "programmer"),
new User("Jane", "accountant"), new User("Robert", "teacher"),
new User("Milan", "programmer"), new User("Jane", "designer"));
var userNames = users.stream().map(user -> user.getName()).sorted()
.collect(Collectors.toList());
System.out.println(userNames);
var occupations = users.stream().map(user -> user.getOccupation())
.sorted(Comparator.reverseOrder()).distinct()
.collect(Collectors.toList());
System.out.println(occupations);
}
}
该示例以相反的顺序从用户列表和唯一职业列表中创建排序名称列表。
[Jane, Jane, Milan, Peter, Robert]
[teacher, programmer, designer, accountant]
这是输出。
在本教程中,我们已经使用 Java 流映射操作。 您可能也对相关教程感兴趣: Java 流 , Java 流归约 , Java 流过滤器, Java8 forEach
教程, 和用 Java 过滤列表。