ZetCode-Java-教程-三-

ZetCode Java 教程(三)

原文:ZetCode

协议:CC BY-NC-SA 4.0

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 强大。 FilelistFiles()返回给定目录中的文件对象数组。

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 附加到文件。 我们使用FileWriterFileOutputStreamFilesRandomAccessFile,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是用于将数据写入FileFileDescriptor的输出流。 它带有一个可选的第二个参数,该参数确定是否将数据附加到文件中。

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  );
    }
}

该示例使用了ArrayListget()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);
}

UnaryOperatorapply()方法中,我们使用第一个大写字母还原字符串。

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进行排序

ArrayListsort()方法根据由指定比较器引起的顺序对列表进行排序。

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]);

ArrayListtoArray()用于将列表转换为数组。

流到列表的转换

可以使用收集器将 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 文件读入BufferedImageBufferedImage是存储在内存中的像素矩形。 它是 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

图:Favicon

在本文中,我们已使用 image4j 库读取和写入 ICO 图像。

您可能也对以下相关教程感兴趣: Java 教程Java Swing 教程Android 教程

Java intString的转换

原文:http://zetcode.com/java/inttostring/

Java intString教程展示了如何将整数转换为字符串。 有几种方法可以在 Java 中执行从intString的转换。 我们可以使用字符串连接,字符串格式化,字符串构建以及内置的转换方法。

整数到字符串的转换

整数到字符串的转换是类型转换或类型转换,其中整数数据类型的实体更改为字符串一。

在本教程的示例中,我们构建了一个包含整数的字符串消息。

使用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()进行从intString的转换。

使用字符串连接将int转换为String

当我们在intString参数上使用+运算符时,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()进行从intString的转换。

使用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()进行从intString的转换。

使用StringBuilderint转换为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进行从intString的转换。

Java intString的示例

以下示例使用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);
    }
}

该示例显示了创建StringStringBuilder对象的几种方法。

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 字符串是对象

字符串是对象; 它们不是原始数据类型。 字符串是StringStringBuilder类的实例。 由于它们是对象,因此有多种方法可用于完成各种工作。

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');

StringBuildersetCharAt()方法将用新字符替换给定索引处的字符。 原始字符串被修改。

$ 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中的键/值对。 HashMapentrySet()返回包含在映射中的映射的Set视图。 使用keySet()方法检索一组键。

Java HashMap层次结构

HashMap扩展了AbstractMap并实现了MapMap提供了包括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.ofMap.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 表达式迭代了HashMapforEach()

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。 键必须唯一; 因此,我们有一个SetSet是一个不包含重复元素的集合。

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类增加相同的类变量。 因此,DogCat指的是同一类变量。

int nOfBeings = Being.count;

我们得到所有被创造的生物的数量。 我们通过类名称,后跟点运算符和变量名称来引用类变量。

Java 静态变量属性

  • 静态变量具有默认值。
  • 静态变量可以通过静态和非静态方法直接访问。
  • 静态变量称为类变量或静态字段。
  • 静态变量与类关联,而不与任何对象关联。

Java 静态方法

在没有对象实例的情况下调用静态方法。 要调用静态方法,我们使用类的名称,点运算符和方法的名称。 静态方法只能使用静态变量。 静态方法通常用于表示不会随对象状态变化的数据或计算。 例如,java.lang.Math包含用于各种计算的静态方法。

我们使用static关键字声明一个静态方法。 如果不存在static修饰符,则该方法称为实例方法。

静态方法限制

静态方法只能调用其他静态方法。 它们只能访问静态数据,而不能引用thissuper

静态方法示例

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中的键/值对。 HashMapentrySet()返回包含在映射中的映射的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 表达式迭代了HashMapforEach()

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变量。

使用IteratorHashMap迭代

在下面的示例中,我们使用IteratorMap.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

在下一个示例中,我们使用HashMapkeySet()方法在迭代器上迭代键集,该方法返回此映射中包含的键的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。 键必须唯一; 因此,我们有一个SetSet是一个不包含重复元素的集合。

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()遍历集合。

在包含ArrayListHashMap上进行迭代

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 类:agenamesex

使用 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 兼容的ListSetMap实现,并具有丰富的 API,在 JDK 中找不到的其他类型(例如BagsMultimaps)以及与所有与 JDK 兼容的任何工具CollectionsArraysMapsStrings

<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 保持为最小。

它在ListSetMap接口上包含新的静态工厂方法,用于创建集合的不可修改实例。

安装 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 project structure

图: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()返回nk的二项式系数。

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 的StringJoinerOpencsv 教程

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();

使用CsvToBeanparse()方法,我们将 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;

我们有三个数组声明。 该声明包括两部分:数组的类型和数组的名称。 数组的类型具有确定数组中元素的类型(在我们的情况下为intStringfloat)的数据类型,并带有一对方括号[]。 方括号表示我们有一个数组。

集合具有类似数组的作用。 它们比数组更强大。 稍后将在单独的章节中进行介绍。

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数组有两个内部数组。 内部数组的元素等于ab数组。

int[][] d = {
    a,
    b
};

d数组包含对ab数组的引用。

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");
}

现在,使用这两种方法比较cd数组。 对于equals()方法,数组不相等。 deepEquals()方法在引用数组中更深入,并检索它们的元素以进行比较。 对于此方法,cd数组相等。

$ 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接口定义了一些方法,我们可以通过这些方法枚举(一次获得一个元素)对象集合中的元素。 两个主要的集合类是VectorHashtable

今天,EnumerationVectorHashtable被认为已过时。 但是,它们不被弃用。

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 引入了标准集合类(ListSetMap)和IteratorIterator带来了迭代器设计模式,这是一种常见的行为模式,用于按顺序访问集合对象的元素,而无需了解其基础表示。

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类; 它具有namepopulation属性。

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 字符串时,使用StringBuilderStringBuffer是类似于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);
    }
}

该示例演示了StringStringBuilder之间的主要区别。

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 中拆分字符串。 我们使用Stringsplit()PatternsplitAsStream()和 Guava Splitteron()方法。

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);
    }
}

该示例使用PatternsplitAsStream()方法拆分电话号码。

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.UPRoundingMode.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对象。

时间是日期,时间和偏移对象的基本接口类型,包括LocalDateLocalTimeLocalDateTimeInstant

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()) {

我们使用Fileexists()方法检查文件是否存在。

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_KBFileUtils.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()查找与txthtml扩展名匹配的文件。

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 表达式的主体中,我们检查值是否不是nullcollect()方法是一种终端操作,可从过滤后的流中创建列表。

[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 reduceOptional

具有一个参数的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 过滤列表

posted @ 2024-10-24 18:16  绝不原创的飞龙  阅读(3)  评论(0编辑  收藏  举报