百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

10 大 Java 语言特性(java语言具体跨平台的特性。)

toyiye 2024-09-14 13:31 3 浏览 0 评论

让我们探讨一下开发人员在日常编程工作中经常使用的十个 Java 编程特性。


每种编程语言都提供了表达我们的想法并将其转化为现实的方法。

有些是该特定语言所独有的,有些是许多其他编程语言所共有的。

在本文中,我将探讨开发人员在日常编程工作中经常使用的十个 Java 编程特性。

集合的工厂方法

集合是我们日常编码中最常用的功能。它们被用作我们存储对象并传递它们的容器。

集合还用于对对象进行排序、搜索和迭代,使程序员的生活更轻松。它提供了一些基本的接口,如List、Set、Map等,以及多种实现。

传统的创建方式对许多开发人员Collections来说Maps可能看起来很冗长。

这就是为什么 Java 9 引入了一些非常简洁的工厂方法。

List:

List countries = List.of("Bangladesh", "Canada", "United States", "Tuvalu");

Set:

Set countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");

Map:

Map<String, Integer> countriesByPopulation = Map.of("Bangladesh", 164_689_383,
                                                            "Canada", 37_742_154,
                                                            "United States", 331_002_651,
                                                            "Tuvalu", 11_792);

当我们想要创建不可变容器时,这些非常方便。但是,如果我们要创建可变集合,建议使用传统方法。

如果您想了解有关集合框架的更多信息,请访问此处:集合框架。

本地类型推断

Java 10 引入了对局部变量的类型推断,这对开发者来说超级方便。

传统上,Java 是一种强类型语言,开发人员在声明和初始化对象时必须指定两次类型。似乎很乏味。看下面的例子:

Map<String, Map<String, Integer>> properties = new HashMap<>();

我们在上述声明中指定了双方的信息类型。如果我们在一个地方定义它,我们的眼睛很容易解释这必须是一种Map类型。Java 语言已经足够成熟,Java 编译器应该足够聪明,可以理解这一点。本地类型推断正是这样做的。
上面的代码现在可以写成如下:

var properties = new HashMap<String, Map<String, Integer>>();

现在我们必须编写和键入一次。上面的代码可能看起来并没有那么糟糕。但是,当我们调用方法并将结果存储在变量中时,它会缩短很多。例子:

var properties = getProperties();

相似地,

var countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");

尽管这似乎是一个方便的功能,但也有一些批评。一些开发人员会争辩说,这可能会降低可读性,这比这个小便利更重要。

要了解更多信息,请访问:

打开 JDK Lvti-Faq

打开 JDK Lvti-style-guide

增强的开关表达式

传统的 switch 语句从一开始就在 Java 中,类似于 C 和 C++。没关系,但是随着语言的发展,它直到 Java 14 才为我们提供任何改进。它当然也有一些限制。最臭名昭著的是跌倒:

为了解决这个问题,我们使用了 break 语句,它们几乎是样板代码。但是,Java 14 引入了一种查看此 switch 语句的新方法,并提供了许多更丰富的功能。

我们不再需要添加 break 语句;它解决了跌倒问题。最重要的是,switch 语句可以返回一个值,这意味着我们可以将其用作表达式并将其分配给变量。

爪哇

int day = 5;
String result = switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> "Unexpected value: " + day;
};

阅读有关它的更多信息:使用 Switch 表达式进行分支

记录

尽管记录是 Java 中相对较新的功能,在 Java 16 中发布,但许多开发人员发现创建不可变对象非常有用。

我们经常需要在我们的程序中使用数据职业对象来保存或将值从一种方法传递到另一种方法。例如,一个携带 x、y 和 z 坐标的类,我们将其编写如下。

package ca.bazlur.playground;

import java.util.Objects;

public final class Point {
    private final int x;
    private final int y;
    private final int z;

    public Point(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int x() {
        return x;
    }

    public int y() {
        return y;
    }

    public int z() {
        return z;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (obj == null || obj.getClass() != this.getClass()) return false;
        var that = (Point) obj;
        return this.x == that.x &&
                this.y == that.y &&
                this.z == that.z;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y, z);
    }

    @Override
    public String toString() {
        return "Point[" +
                "x=" + x + ", " +
                "y=" + y + ", " +
                "z=" + z + ']';
    }

}

这门课看起来超级冗长,与我们的整个意图无关。整个代码可以用以下代码替换 -


package ca.bazlur.playground;

public record Point(int x, int y, int z) {
}

在此处阅读有关记录的更多信息:Java 记录语义https://nipafx.dev/java-record-semantics/

可选的

方法是一种契约:我们在定义它时会考虑到它。我们指定参数及其类型以及返回类型。当我们调用一个方法时,我们期望它按照约定行事。如果没有,则违反合同。

但是,我们经常从方法中获取 null 而不是指定类型的值。这是违规行为。调用者不能预先知道,除非它调用它。为了解决这种违规,调用程序通常使用 if 条件测试该值,无论该值是否为空。例子:

public class Playground {

    public static void main(String[] args) {
        String name = findName();
        if (name != null) {
            System.out.println("Length of the name : " + name.length());
        }
    }

    public static String findName() {
        return null;
    }
}

看上面的代码。该findName()方法应该返回一个String值,但它返回 null。调用者现在必须先检查空值才能处理它。如果调用忘记这样做,他们最终会得到NullPointerException不是预期的行为。

另一方面,如果方法签名指定了不能返回值的可能性,它将解决所有的混乱。这就是Optional发挥作用的地方。

import java.util.Optional;

public class Playground {

    public static void main(String[] args) {
        Optional<String> optionalName = findName();
        optionalName.ifPresent(name -> {
            System.out.println("Length of the name : " + name.length());
        });
    }

    public static Optional<String> findName() {
        return Optional.empty();
    }
}

现在我们findName()用 Optional 重写了方法,它指定了不返回任何值的可能性,我们可以处理它。这会向程序员发出预先警告并修复违规行为。

阅读更多关于可选的

Java 日期时间 API

每个开发人员都在某种程度上对日期时间计算感到困惑。这不是夸大其词。这主要是由于长期以来没有一个好的 Java API 来处理 Java 中的日期和时间。

然而,这个问题不再存在,因为 Java 8 在java.time包中带来了一套出色的 API,可以解决所有与日期和时间相关的问题。

java.time包提供了许多接口和类来解决处理日期和时间的大多数问题,包括时区(有时会非常复杂)。但是,我们主要使用以下类 -

  • 本地日期
  • 当地时间
  • 本地日期时间
  • 期间
  • 时期
  • ZonedDateTime 等

这些类旨在具有通常需要的所有方法。例如

import java.time.LocalDate;
import java.time.Month;

public class Playground3 {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2022, Month.APRIL, 4);
        System.out.println("year = " + date.getYear());
        System.out.println("month = " + date.getMonth());
        System.out.println("DayOfMonth = " + date.getDayOfMonth());
        System.out.println("DayOfWeek = " + date.getDayOfWeek());
        System.out.println("isLeapYear = " + date.isLeapYear());
    }
}

同样,LocalTime 具有计算时间所需的所有方法。

LocalTime time = LocalTime.of(20, 30);
int hour = time.getHour(); 
int minute = time.getMinute(); 
time = time.withSecond(6); 
time = time.plusMinutes(3);

我们可以将它们结合起来-

LocalDateTime dateTime1 = LocalDateTime.of(2022, Month.APRIL, 4, 20, 30);
LocalDateTime dateTime2 = LocalDateTime.of(date, time);

我们如何包括时区-

ZoneId zone = ZoneId.of("Canada/Eastern");
LocalDate localDate = LocalDate.of(2022, Month.APRIL, 4);
ZonedDateTime zonedDateTime = date.atStartOfDay(zone);

阅读有关 Java 日期时间的更多信息

有用的 NullPointerException

每个开发人员都讨厌空指针异常。当 StackTrace 不提供有用的信息时,它变得具有挑战性。为了演示这个问题,让我们看一个例子:

package com.bazlur;

public class Main {

    public static void main(String[] args) {
        User user = null;
        getLengthOfUsersName(user);
    }

    public static void getLengthOfUsersName(User user) {
        System.out.println("Length of first name: " + user.getName().getFirstName());
    }
}

class User {
    private Name name;
    private String email;

    public User(Name name, String email) {
        this.name = name;
        this.email = email;
    }

   //getter
   //setter
}

class Name {
    private String firstName;
    private String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

   //getter
   //setter
}

看上面代码的main方法。我们可以看到我们会得到一个空指针异常。如果我们使用 pre-Java 14 运行和编译代码,我们将获得以下 StackTrace:


Exception in thread "main" java.lang.NullPointerException
at com.bazlur.Main.getLengthOfUsersName(Main.java:11)
at com.bazlur.Main.main(Main.java:7)

这个堆栈跟踪是可以的,但是它没有太多关于这个 NullPointerException 发生在哪里以及为什么发生的信息。

但是,在 Java 14 及更高版本中,我们可以在堆栈跟踪中获得更多信息,这非常方便。在 Java 14 中,我们将获得:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "ca.bazlur.playground.User.getName()" because "user" is null
at ca.bazlur.playground.Main.getLengthOfUsersName(Main.java:12)
at ca.bazlur.playground.Main.main(Main.java:8)

阅读更多关于它的信息。

可完成的未来

我们逐行编写程序,通常它们会逐行执行。但是,有时我们希望相对并行执行以使程序更快。为此,我们通常参考 Java 线程。

好吧,Java 线程编程并不总是与并行编程有关。相反,它为我们提供了一种组合程序的多个独立单元以独立执行以与其他单元一起取得进展的方法,并且它们通常是异步运行的。

然而,线程编程及其复杂性似乎很可怕。大多数初级和中级开发人员都在为此苦苦挣扎。这就是为什么 Java 8 带来了一个更直接的 API,让我们可以完成程序的一部分异步运行。让我们看一个例子:

假设我们必须调用三个 REST API,然后组合结果。我们可以一一称呼。如果它们每个都需要大约 200 毫秒,那么获取所有它们的总时间将需要 600 毫秒。

如果我们可以并行运行它们会怎样?由于现代 CPU 中包含多核,因此它们可以轻松处理三个不同 CPU 上的三个休息调用。使用 CompletableFuture,我们可以轻松实现这一点。

爪哇

package ca.bazlur.playground;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class SocialMediaService {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        var service = new SocialMediaService();

        var start = Instant.now();
        var posts = service.fetchAllPost().get();
        var duration = Duration.between(start, Instant.now());

        System.out.println("Total time taken: " + duration.toMillis());
    }

    public CompletableFuture<List<String>> fetchAllPost() {
        var facebook = CompletableFuture.supplyAsync(this::fetchPostFromFacebook);
        var linkedIn = CompletableFuture.supplyAsync(this::fetchPostFromLinkedIn);
        var twitter = CompletableFuture.supplyAsync(this::fetchPostFromTwitter);

        var futures = List.of(facebook, linkedIn, twitter);

        return CompletableFuture.allOf(futures.toArray(futures.toArray(new CompletableFuture[0])))
                .thenApply(future -> futures.stream()
                        .map(CompletableFuture::join)
                        .toList());
    }
    private String fetchPostFromTwitter() {
        sleep(200);
        return "Twitter";
    }

    private String fetchPostFromLinkedIn() {
        sleep(200);
        return "LinkedIn";
    }

    private String fetchPostFromFacebook() {
        sleep(200);
        return "Facebook";
    }

    private void sleep(int millis) {
        try {
            TimeUnit.MILLISECONDS.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

阅读更多关于它的信息。

Lambda 表达式

Lambda 表达式可能是 Java 语言中最强大的功能。它重塑了我们编写代码的方式。Lambda 表达式就像一个匿名函数,可以接受参数并返回一个值。

我们可以将函数分配给一个变量,并将它作为参数传递给一个方法,一个方法可以返回它。它有一个身体。与方法的唯一区别是它没有名称。

表达简短而简洁。它通常不包含太多样板代码。让我们看一个例子:

我们想列出扩展名为 .java 的目录中的所有文件。

爪哇

var directory = new File("./src/main/java/ca/bazlur/playground");
String[] list = directory.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".java");
    }
});

如果您仔细查看这段代码,我们将匿名内部类传递给方法list()。在内部类中,我们放置了过滤掉文件的逻辑。

本质上,我们对这段逻辑感兴趣,而不是围绕逻辑的样板。

事实上,lambda 表达式允许我们删除所有样板,我们可以编写我们关心的代码。例子:

var directory = new File("./src/main/java/ca/bazlur/playground");
String[] list = directory.list((dir, name) -> name.endsWith(“.java"));

好吧,我只是在这里向您展示了一个示例,但是 lambda 表达式还有很多其他好处。

阅读更多关于它的信息。

流 API

“Lambda 表达式是通向 Java 8 的入门药物,但 Streams 才是真正的瘾。”
- 文卡特·苏布拉马尼亚姆。

在我们的日常编程工作中,我们经常做的一项常见任务是处理一组数据。有一些常见的操作,例如过滤、转换和收集结果。

在 Java 8 之前,这类操作本质上是必不可少的。我们必须为我们的意图(也就是我们想要实现的目标)以及我们想要的方式编写代码。

随着 Lambda 表达式和流 API 的发明,我们现在可以以声明方式编写数据处理功能。我们只指定我们的意图,但我们不必写下我们如何得到结果。让我们看一个例子:

我们有一个书籍列表,我们希望找到所有 Java 书籍的名称,这些名称以逗号分隔和排序。

public static String getJavaBooks(List<Book> books) {
    return books.stream()
            .filter(book -> Objects.equals(book.language(), "Java"))
            .sorted(Comparator.comparing(Book::price))
            .map(Book::name)
            .collect(Collectors.joining(", "));
}

上面的代码简单、易读、简洁。替代的命令式代码是-

public static String getJavaBooksImperatively(List<Book> books) {
    var filteredBook = new ArrayList<Book>();
    for (Book book : books) {
        if (Objects.equals(book.language(), "Java")){
            filteredBook.add(book);
        }
    }
    filteredBook.sort(new Comparator<Book>() {
        @Override
        public int compare(Book o1, Book o2) {
            return Integer.compare(o1.price(), o2.price());
        }
    });

    var joiner = new StringJoiner(",");
    for (Book book : filteredBook) {
        joiner.add(book.name());
    }
    
    return joiner.toString();
}

虽然这两种方法返回相同的值,但我们清楚地看到了区别。

了解有关流 API 的更多信息

这就是今天的全部内容。干杯!

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码