java 应用分模块_在Java 11中创建一个简单的模块化应用教程

模块化编程使人们能够将代码组织成独立的,有凝聚力的模块,这些模块可以组合在一起以实现所需的功能。

本文摘自Nick Samoylov和Mohamed Sanaulla撰写的一本名为Java 11 Cookbook - Second Edition的书。在本书中,您将学习如何使用Java 11中的类和接口实现面向对象的设计 。

可以在GitHub上找到本教程中显示的示例的完整代码。

您应该想知道这种模块化是什么,以及如何使用Java创建模块化应用程序 。在本文中,我们将通过一个简单的示例来尝试清除在Java中创建模块化应用程序的困惑 。我们的目标是向您展示如何创建模块化应用程序; 因此,我们选择了一个简单的例子,以便专注于我们的目标。

做什么

我们的示例是一个简单的高级计算器,它检查数字是否为素数,计算素数之和,检查数字是否为偶数,并计算偶数和奇数之和。

做好准备

我们将应用程序分为两个模块:

math.util模块包含用于执行数学计算的API

calculator模块启动了一个高级计算器

怎么做

1. 让我们实现com.packt.math.MathUtil中的API,从isPrime(Integer number)API开始:public static Boolean isPrime(Integer number){

if ( number == 1 ) { return false; }

return IntStream.range(2,num).noneMatch(i -> num % i == 0 );

}

2. 实现sumOfFirstNPrimes(Integer count)

public static Integer sumOfFirstNPrimes(Integer count){

return IntStream.iterate(1,i -> i+1)

.filter(j -> isPrime(j))

.limit(count).sum();

}

3. 让我们写一个函数来检查数字是否是偶数:

public static Boolean isEven(Integer number){

return number % 2 == 0;

}

4. 非isEven结果告诉我们这个数字是否是奇数。我们可以使用函数来查找前N个偶数和前N个奇数之和,如下所示:

public static Integer sumOfFirstNEvens(Integer count){

return IntStream.iterate(1,i -> i+1)

.filter(j -> isEven(j))

.limit(count).sum();

}

public static Integer sumOfFirstNOdds(Integer count){

return IntStream.iterate(1,i -> i+1) .filter(j -> !isEven(j)) .limit(count).sum();

}

我们可以在前面的API中看到重复以下操作:

从数字1开始的无限数字序列

根据某些条件过滤数字

将流的数量限制为给定的计数

找到由此获得的数字之和

根据我们的观察,我们可以重构前面的API并将这些操作提取到一个方法中,如下所示:

Integer computeFirstNSum(Integer count,

IntPredicate filter){

return IntStream.iterate(1,i  - > i + 1)

.filter(filter)

.limit(count).sum();

}

这里  count是我们需要找到的总和的数量限制,并且  filter是选择求和数的条件。

让我们根据刚刚进行的重构重写API:

public static Integer sumOfFirstNPrimes(Integer count){ return computeFirstNSum(count, (i -> isPrime(i))); }

public static Integer sumOfFirstNEvens(Integer count){ return computeFirstNSum(count, (i -> isEven(i))); } public static Integer sumOfFirstNOdds(Integer count){ return computeFirstNSum(count, (i -> !isEven(i)));

到目前为止,我们已经看到了一些围绕数学计算的API。

开始正题

让我们将这个小实用程序类作为名为的模块的一部分  math.util。以下是我们用于创建模块的一些约定:

将与模块相关的所有代码放在一个名为的目录下math.util,并将其视为我们的模块根目录。

在根文件夹中,插入名为module-info.java.的文件

将包和代码文件放在根目录下。

module-info.java包含什么?

模块的名称

它导出的包,即可供其他模块使用的包

它依赖的模块

它使用的服务

它为其提供实施的服务

我们的math.util模块不依赖于任何其他模块(当然,java.base模块除外)。但是,它使其API可用于其他模块(如果没有,那么这个模块的存在是有问题的)。让我们继续把这个陈述放到代码中:

module math.util {

exports com.packt.math;

}

我们告诉Java编译器和运行时我们的math.util 模块正在将com.packt.math包中的代码导出到任何依赖的模块math.util。

可以在以下位置找到此模块的代码  Chapter03/2_simple-modular-math-util/math.util。

现在,让我们创建另一个使用该math.util模块的模块计算器。该模块有一个Calculator类,其工作是接受用户选择执行哪个数学运算,然后执行操作所需的输入。用户可以从五种可用的数学运算中进行选择:

素数检查

偶数号检查

N素数总和

N偶数总和

N奇数总和

我们在代码中看到这个:

private static Integer acceptChoice(Scanner reader){

System.out.println("************Advanced Calculator************");

System.out.println("1. Prime Number check");

System.out.println("2. Even Number check");

System.out.println("3. Sum of N Primes");

System.out.println("4. Sum of N Evens");

System.out.println("5. Sum of N Odds");

System.out.println("6. Exit");

System.out.println("Enter the number to choose operation");

return reader.nextInt();

}

然后,对于每个选项,我们接受所需的输入并调用相应的MathUtilAPI,如下所示:

switch(choice){

case 1:

System.out.println("Enter the number");

Integer number = reader.nextInt();

if (MathUtil.isPrime(number)){

System.out.println("The number "+ number +" is prime");

}else{

System.out.println("The number "+ number +" is not prime");

}

break;

case 2:

System.out.println("Enter the number");

Integer number = reader.nextInt();

if (MathUtil.isEven(number)){

System.out.println("The number "+ number +" is even");

}

break;

case 3:

System.out.println("How many primes?");

Integer count = reader.nextInt();

System.out.println(String.format("Sum of %d primes is %d",

count, MathUtil.sumOfFirstNPrimes(count)));

break;

case 4:

System.out.println("How many evens?");

Integer count = reader.nextInt();

System.out.println(String.format("Sum of %d evens is %d",

count, MathUtil.sumOfFirstNEvens(count)));

break;

case 5:

System.out.println("How many odds?");

Integer count = reader.nextInt();

System.out.println(String.format("Sum of %d odds is %d",

count, MathUtil.sumOfFirstNOdds(count)));

break;

}

让我们calculator以与为模块创建模块相同的方式为模块创建模块定义math.util:

module calculator{

requires math.util;

}

在前面的模块定义中,我们提到  calculator模块依赖于  math.util模块使用  required 关键字。

让我们编译代码:

javac -d mods --module-source-path . $(find . -name "*.java")

--module-source-path 命令是  javac新的命令行选项,用于指定模块源代码的位置。

让我们执行前面的代码:

java --module-path mods -m calculator/com.packt.calculator.Calculator

--module-path 命令类似于--classpath,是新java的命令行选项   ,指定已编译模块的位置。

运行上述命令后,您将看到计算器正在运行。

我们提供了脚本来测试Windows和Linux平台上的代码 。请使用run.bat用于Windows和run.sh用于 Linux的。

原理

现在您已经完成了示例,我们将了解如何对其进行概括,以便我们可以在所有模块中应用相同的模式。我们遵循特定的约定来创建模块:

| application_root_directory

| --module1_root

| ---- module-info.java

| ---- com

| ------ packt

| -------- sample

| --------- -MyClass.java

| --module2_root

| ---- module-info.java

| ---- com

| ------ packt

| -------- test

| ------- ---MyAnotherClass.java

我们将特定于模块的代码放在其文件夹中,并在文件夹module-info.java 的根目录下放置相应的文件。这样,代码组织得很好。

{Annotation} [open] module ModuleName {{ModuleStatement}}

这是语法,解释如下:

{Annotation}:这是表单的任何注释@Annotation(2)。

open:此关键字是可选的。开放模块通过反射在运行时访问其所有组件。但是,在编译时和运行时,只能访问显式导出的那些组件。

module:这是用于声明模块的关键字。

ModuleName:这是模块的名称,该模块是有效的Java标识符,.在标识符名称之间允许使用dot() - 类似于  math.util。

{ModuleStatement}:这是模块定义中允许的语句的集合。让我们接下来展开。

模块语句具有以下形式:

ModuleStatement:

requires {RequiresModifier} ModuleName ;

exports PackageName [to ModuleName {, ModuleName}] ;

opens PackageName [to ModuleName {, ModuleName}] ;

uses TypeName ;

provides TypeName with TypeName {, TypeName} ;

模块语句在这里被解码:

requires:这用于声明对模块的依赖。{RequiresModifier}可以是传递的,静态的,或两者兼而有之。传递意味着依赖于给定模块的任何模块也隐式地依赖于给定模块传递所需的模块。静态意味着模块依赖在编译时是必需的,但在运行时是可选的。一些例子是  requires math.util,requires transitive math.util和  requires static math.util。

exports:这用于使依赖模块可以访问给定的包。或者,我们可以通过指定模块名称来强制包对特定模块的可访问性,例如  exports com.package.math to claculator。

opens:这用于打开特定包。我们之前看到,我们可以通过open使用模块声明指定关键字来打开模块。但这可能是限制性较小的。因此,为了使其更具限制性,我们可以使用openskeyword- 在运行时打开一个特定的反射访问包opens com.packt.math。

uses:这用于声明可通过可访问的服务接口的依赖项java.util.ServiceLoader。服务接口可以位于当前模块中,也可以位于当前模块所依赖的任何模块中。

provides:这用于声明服务接口并为其提供至少一个实现。可以在当前模块或任何其他相关模块中声明服务接口。但是,必须在同一模块中提供服务实现; 否则,将发生编译时错误。

我们将在使用服务中更详细地查看uses和provides子句,  以在消费者和提供者模块  配方之间创建松散耦合。

可以使用--module-source-path命令行选项一次编译所有模块的模块源。这样,所有模块都将被编译并放置在该-d选项提供的目录下的相应目录中。例如,  javac -d mods --module-source-path . $(find . -name "*.java") 将当前目录中的代码编译到mods 目录中。

运行代码同样简单。我们使用命令行选项指定编译所有模块的路径  --module-path。然后,我们使用命令行选项提及模块名称以及完全限定的主类名称  -m,例如  java --module-path mods -m calculator/com.packt.calculator.Calculator。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java选课系统_java实现学生选课系统

本文为大家分享了java实现学生选课系统的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下案例要求&#xff1a;学生(学号&#xff0c;姓名&#xff0c;专业&#xff0c;所选课程{<3})老师(工号&#xff0c;姓名&#xff0c;所教课程{<3})课程(课程号&#xff0c…

mysql 推送微信公众号_10分钟完成微信公众号第三方平台全网发布

背景&#xff1a;在微信公众平台配置服务器URL时&#xff0c;使用了新浪云SAE自带的二级域名&#xff0c;提交时出现一个安全风险的警告&#xff0c;网上查了下&#xff0c;许多服务平台和团队也遇到同样的问题。经过一番研究 …为什么会有安全风险的警告&#xff1f;微信公众平…

mysql 查询 带数据库实例_数据库查询实例(包含所有where条件例子)

查询指定列[例1] 查询全体学生的学号与姓名。SELECT Sno&#xff0c;SnameFROM Student&#xff1b;[例2] 查询全体学生的姓名、学号、所在系。SELECT Sname&#xff0c;Sno&#xff0c;SdeptFROM Student&#xff1b;[例3] 查询全体学生的详细记录。SELECT Sno&#xff0c;Sna…

python if and函数_逻辑函数And,OR,IF

越是碎片化时代&#xff0c;越是要进行系统化学习&#xff01;今天7月22日E战到底训练营打卡第十&#xff0c;今天学的是《逻辑函数And,or,if》也是一个非常实用的技能.在许多数据处理中都可以发挥很大作用。一.介绍了逻辑值&#xff1a;true false&#xff0c;分别代表真(成立…

java集合总结_java集合小总结

java集合就是一个容器。1. 集合概述l 为了保存不确定的数据&#xff0c;或者对象&#xff0c;以及保存具有映射关系的数据。l 所有的集合类都位于java.util包下。1.1. 什么是集合&#xff0c;有什么特点&#xff1f;面向对象语言对事物的体现都是以对象的形式存…

java排序算法原理_排序算法原理与实现(java)

排序算法原理与实现(java) Java程序员必知的8大排序 [来源&#xff1a;本站 | 日期&#xff1a;2012年12月24日 | 浏览173 次] 字体:[大 中 小] 8种排序之间的关系: 1&#xff0c; 直接插入排序 (1)基本思想&#xff1a;在要排序的一组数中&#xff0c;假设前面(n-1)[n>2] 个…

python表示当前目录_从Python脚本获取当前目录的父项

使用os.path要获取包含脚本的目录的父目录(无论当前工作目录如何),您需要使用__file__.from os.path import dirname, abspathd dirname(dirname(abspath(__file__))) # /home/kristina/desire-directory基本上,您可以通过根据需要多次调用os.path.dirname来走向目录树.例&…

ios django 连接mysql_Django---Django连接Mysql数据库

前面介绍了Django平台的数据交互&#xff0c;这些数据都是在本地存放着&#xff0c;修改内容或者重新启动服务&#xff0c;数据就消失了&#xff0c;如果我们把数据存放在数据库中&#xff0c;不就保存了吗&#xff1f;Django数据库Django中自带的也有数据库(sqlite3)&#xff…

java io流操作_【Java基础】IO流操作

一、IO流概念&#xff1a; 输入输出流&#xff0c;也就是可以用来读写数据&#xff0c;以及上传下载数据。二、分类&#xff1a;1、从流的对象来分&#xff1a; 1)高端流&#xff1a;所有程序或者内存中的流都称为高端流。2)低端流&#xff1a;所有外界设备中的流都是低端流。…

java xmpp openfire_XMPP协议学习笔记三(Openfire服务器端搭建开发环境)

在了解了XMPP的基本结构和一些概念之后&#xff0c;我们暂时告别枯燥的理论学习&#xff0c;来动手搭建一下OpenfireSpark的开发环境&#xff0c;实际感受一下搭建整套IM通讯系统的过程。开发环境&#xff1a;windows XP sp3&#xff0c;Eclipse3.6.1&#xff0c;jdk1.6.0_24&a…

快速排序 java导包_排序算法-快速排序(Java实现)

上篇我们讲了冒泡排序&#xff0c;这次我们讲它的升级版快速排序&#xff0c;“快速”&#xff0c;一看就是个好算法~快速排序(QuickSort)是啥&#xff1f;我们先看下百度百科的介绍快速排序(Quicksort)是对冒泡排序的一种改进。快速排序由C. A. R. Hoare在1962年提出。它的基本…

java怎么判断一个char是汉字_JAVA中判断char是否是中文的几种方法

展开全部对照最新版本的 Unicode (最少是62616964757a686964616fe59b9ee7ad9431333335343330 6.0 版本&#xff0c;不知道现在是否有 7.0) 里面找从哪个 code point 数字开始到哪个数字结束的是常用中文汉字&#xff0c;另外冷僻汉字肯定不是用单个 char 能表示的&#xff0c;…

java接口经常变动前端怎么办_Java进程故障排查(CPU资源占用高,接口响应超时,功能接口停滞等)...

故障分析# 导致系统不可用情况(频率较大)&#xff1a;1)代码中某个位置读取数据量较大&#xff0c;导致系统内存耗尽&#xff0c;进而出现Full GC次数过多&#xff0c;系统缓慢&#xff1b;2)代码中有比较消耗CPU的操作&#xff0c;导致CPU过高&#xff0c;系统运行缓慢&#x…

使用java实现面向对象编程第二章_java面向对象编程——第二章 java基础语法

第二章java基础语法1、java关键字abstractbooleanbreakbytecasecatchcharclassconstcontinuedefaultdodoubleelseextendsassertfinalfinallyfloatforgotoifimplementsimportinstanceofintinterfacelongnativenewstrictfppackageprivateprotectedpublicreturnshortstaticsupersw…

mysql 二维数组下标_php二维数组指定下标排序

/** Effect 排序* author YangYunHao* email 1126420614qq.com* time 2018-11-26 11:59:38* parameter arr:排序数组,key:按什么排,type:升序降序* */function arraySort($arr,$key,$typeasc){$keyArr []; // 初始化存放数组将要排序的字段值foreach ($arr as $k>$v){$keyA…

用java实现楼层导航_JS实现网站楼层导航效果代码实例

壹 ❀ 引言对于楼层导航而言&#xff0c;还有个重要的功能就是&#xff0c;随着滚动条滚动&#xff0c;达到某层时得同步点亮楼层导航的小图片。由于我前面也说了不打算使用JQ&#xff0c;所以想着用JS去实现它&#xff0c;实现并不难&#xff0c;主要得弄清滚动满足怎样的条件…

费尔马小定理素数java_利用费马小定理判断素数

今天听了ljss神犇的数论课&#xff0c;顿时感觉————我真的是太弱啦&#xff01;我只能稍微写一下我能听懂的部分orz那么这就是今天我为数不多能听懂一点的之一......QAQ首先先介绍今天的主角&#xff1a;费马小定理————转自维基百科没看懂的话我稍微解释一下&#xff0…

java读取一段缓存音频文件夹_java实现酷狗音乐临时缓存文件转换为MP3文件的方法...

本文实例讲述了java实现酷狗音乐临时缓存文件转换为MP3文件的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;酷狗临时缓存文件&#xff0c;其实已经是吧MP3文件下载好了&#xff0c;只是名字看上去好像是通过md5算法重命名的。酷狗在缓存文件的时候会同时缓存歌词…

java aspectj_AspectJ基本用法

AOP虽然是方法论&#xff0c;但就好像OOP中的Java一样&#xff0c;一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ了&#xff0c;它是一种几乎和Java完全一样的语言&#xff0c;而且完全兼容Java(AspectJ应该就是一种扩展Java&#xff0c;但它不是像Groovy…

php连接数据库返回数据类型,php从数据库读取数据,并以json格式返回数据的方法...

php中&#xff0c;从数据库读取数据&#xff0c;并以json格式返回数据。具体方法如下&#xff1a;第一步&#xff0c;定义相关变量$servername "localhost";$username "root";$password "root";$mysqlname "datatest";$json ;$da…