当您熟悉 Streams 的操作时,您可能已经注意到与 SQL 构造的相似之处。 它们中的一些或多或少直接映射到 Stream 操作,例如 LIMIT 和 COUNT。开源项目 Speedment 利用这种相似性,使用纯 Java 对任何关系数据库提供类型安全的访问。
官网:https://speedment.com/
工具
JDK 8.0.40或更高版本
ApacheMaven 3.3.9或更高版本
开始前准备
- 解压下载的demo.zip
解压后会有个空的main文件夹,后续生成的代码将会放入其中
到pom所在的文件下执行mvn speedment:tool
这里的pom最好替换成如下的(主要是数据源换成mysql):
<?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.speedment</groupId>
<artifactId>documentation-examples</artifactId>
<version>3.0.21</version>
<packaging>jar</packaging>
<name>Speedment - Documentation - Examples</name>
<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>
<speedment.version>3.2.10</speedment.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.speedment</groupId>
<artifactId>speedment-maven-plugin</artifactId>
<version>${speedment.version}</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.speedment</groupId>
<artifactId>runtime</artifactId>
<version>${speedment.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>speedment-enterprise</id>
<name>Speedment Enterprise Repositories</name>
<url>http://repo.speedment.com/nexus/content/repositories/releases/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>speedment-enterprise</id>
<name>Speedment Enterprise Repositories</name>
<url>http://repo.speedment.com/nexus/content/repositories/releases/</url>
</pluginRepository>
</pluginRepositories>
</project>
本人在这一步非常脸黑的遇到了三个错误 没有遇到的请跳过:
- 第一个是找不到 localRepository,这个的话去settings.xml中找到localRepository配置下就ok了
- 第二个是镜像的问题,本地用的是私服,然后setting中配置成阿里镜像,然后发现还是不行,发现是倚赖版本太高,在pom中还是添加了speedMent的库
- 第三个是根据上面的窗口里的提示 我使用了
mvn speedment:tool -X switch
为了查看具体的出错信息,结果又出现下面的错误:
去掉后缀 执行原语句然后成功,真是出师不利啊。
除了使用命令外也可将zip解压后用idea打开,选择右侧的speedment:tool运行即可
- 执行完后会弹出如下窗口
官方说免费版的能够支持的数据库大小最大为 500M 所以点击start free
填写相关信息进行注册
然后就会弹出连接数据库的界面,下面的教程中大多是翻译的,上述步骤完成后执行下面的步骤一,跳到步骤二的连接数据库部分。
教程1-HelloSpeedment
在本教程中,我们将编写一个小程序,它能够询问用户的姓名和年龄,并将其保存在MySQL数据库中。首先,我们将初始化数据库。
步骤1:建立数据库
CREATE DATABASE hellospeedment;
USE hellospeedment;
我们还将添加一个用于存储信息的表。
CREATE TABLE IF NOT EXISTS `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`age` int(5) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
步骤2:创建一个新的Speedment Maven项目
接下来,我们需要建立一个依赖Speedment的Maven项目,并连接到新创建的数据库。
创建自定义项目启动程序
去我们的起始器生成自定义的pom.xml通过填写项目详细信息来执行项目。
连接到数据库
Speedment使用JSON配置文件从数据库生成Java代码。JSON文件将使用Speedment工具创建。然后执行 mvn speedment:tool 或者在IDE中单击它。
启动后,使用该工具连接到数据库。
Speedment会分析底层数据源的元数据,并自动创建直接反映底层数据源结构(即“域模型”)的代码。只需简单地按下生成-按钮。
搞定了!Speedment为数据库中的每个表生成了模型!如果没出错,你就应该得到这样的结构:
步骤3:编写应用程序
现在我们已经准备好编写应用程序了。打开作为项目启动程序一部分的main.java文件,并编辑它,如下所示: (这个Main.java自己创建)
package com.company.speedment.test.hellospeedment;
/**
*
* @author Your name
*/
public class Main {
public static void main(String... params) {
HellospeedmentApplication app = new HellospeedmentApplicationBuilder()
.withBundle(MySqlBundle.class)
.build();
UserManager users = app.getOrThrow(UserManager.class);
}
}
为了告诉Speedment它将与什么数据库交互,在创建应用程序实例时必须添加连接器包。这是通过调用withBundle(CONNECTOR_BUNDLE)
如前面的示例所示。因为我们使用MySQL,所以我们将添加MySqlBundle
.
这个HellospeedmentApplication实例由Speedment自动生成,并将连接到数据库并为您处理所有初始化工作!如果MySQL数据库中有密码,则需要手动设置该密码,如下所示:
HellospeedmentApplication app = new HellospeedmentApplicationBuilder()
.withBundle(MySqlBundle.class)
.withPassword("YourSuperSecretPassword")
.build();
Speedment非常重视您的安全性,不会将您的密码存储在任何配置文件中。
现在我们将监听用户的输入。为此,我们使用Scanner在标准输入通道上。
final Scanner scn = new Scanner(System.in);
使用Scanner,我们可以向用户询问姓名和年龄。在本教程中,我们将不检查输入的有效性,因此我们只是假设用户输入的所有内容都是正确的。
System.out.print("What is your name? ");
final String name = scn.nextLine();
System.out.print("What is your age? ");
final int age = scn.nextInt();
现在,我们希望将这些信息持久化到数据库中。这是通过创建新实体、设置其值和调用persist()在上面。
users.persist(
users.create()
.setName(name)
.setAge(age)
);
我们也可以对查询做出反应,如果有任何问题,我们可以打印一条消息。例如,如果名称已经被持久化,就可能发生这种情况。
try {
User user = users.create()
.setName(name)
.setAge(age);
user = users.persist(user);
System.out.print("Hello, " + user.getName() + "!");
} catch (SpeedmentException se) {
System.out.print("Why are you so persistent?");
se.printStackTrace();
}
如果您想确切地知道您的persist()命令,您可以按以下方式设置日志记录给应用程序。
HellospeedmentApplication app = new HellospeedmentApplicationBuilder()
.withBundle(MySqlBundle.class)
.withLogging(PERSIST)
.build();
UserManager users = app.getOrThrow(UserManager.class);
users.persist(
users.create()
.setName(name)
.setAge(age)
);
这可能提供以下输出:
What is your name? 洺润
What is your age? 18
2020-09-08T02:11:41.491Z DEBUG [main] (#PERSIST) - INSERT INTO `hellospeedment`.`user` (`id`,`name`,`age`) VALUES (?,?,?) [Long 0, String 洺润, Integer 18]
Hello, 洺润!
如果再次输入相同的名字,可能会得到以下输出:
What is your name? 洺润
What is your age? 16
2020-09-08T02:12:44.720Z DEBUG [main] (#PERSIST) - INSERT INTO `hellospeedment`.`user` (`id`,`name`,`age`) VALUES (?,?,?) [Long 0, String 洺润, Integer 16]
Why are you so persistent?
这里执行完后数据库里可以查看是否已经落表
完整代码如下:
/**
* @Auther: 洺润
* @Date: 2020/9/8
* @Description:
*/
public class Main {
final static Scanner scn = new Scanner(System.in);
public static void main(String... params) {
HellospeedmentApplication app = new HellospeedmentApplicationBuilder()
.withBundle(MySqlBundle.class)
.withPassword("root")
.withLogging(PERSIST)
.build();
UserManager users = app.getOrThrow(UserManager.class);
System.out.print("What is your name? ");
final String name = scn.nextLine();
System.out.print("What is your age? ");
final int age = scn.nextInt();
try {
User user = users.create()
.setName(name)
.setAge(age);
user = users.persist(user);
System.out.print("Hello, " + user.getName() + "!");
} catch (SpeedmentException se) {
System.out.print("Why are you so persistent?");
se.printStackTrace();
}
}
}
教程2-First Stream
本教程介绍了在Speedment应用程序中的一些基本流操作。示例使用的数据来自,Sakila数据库
下载下来导入就完事了, 这里俺用mysql的,导入sakila数据库,前几步都是同样的玩法
步骤1:建立数据库
可以下载Sakila数据库这里。安装说明如下这里.
步骤2:创建一个新的SpeedmentMaven项目
如果这是您第一次使用Speedment,我们将在快速启动指南中解释如何设置一个新的SpeedmentMaven项目启动一个新的SpeedmentMaven项目和连接到数据库.
(注意要新建一个文件夹 要不生成代码时就会把之前的给覆盖掉)
步骤3:编写应用程序
前面的教程详细描述了如何设置Speedment应用程序。基本上,一个简单的示例可以归结为以下步骤。建造app,然后Manager应用程序逻辑所需的app最后 ,app在完成应用程序逻辑时关闭。
public static void main(String... params) {
SakilaApplication app = new SakilaApplicationBuilder()
.withBundle(MySqlBundle.class)
.withPassword("MyPassword")
.build();
FilmManager films = app.getOrThrow(FilmManager.class);
ActorManager actors = app.getOrThrow(ActorManager.class);
FilmActorManager filmActors = app.getOrThrow(FilmActorManager.class);
// your application logic here
app.close();
}
步骤4计算流中的项目数
作为第一个程序,我们来计算PG-13级影片的数量,这是通过使用filtering the stream
,然后counting
来完成的。(肯定就是那俩api了)
long count = films.stream()
.filter(Film.RATING.equal("PG-13"))
.count();
System.out.format("There are %d PG-13 films in the DB", count);
通过在创建应用程序时向应用程序添加日志设置,我们可以跟踪Speedment运行时的内部操作。以下应用程序将在数据库中生成PG-13电影的计数,并记录所执行的SQL操作。
public static void main(String... params) {
SakilaApplication app = new SakilaApplicationBuilder()
.withBundle(MySqlBundle.class)
.withPassword("sakila")
.withLogging(ApplicationBuilder.LogType.STREAM)
.build();
FilmManager films = app.getOrThrow(FilmManager.class);
long count = films.stream()
.filter(Film.RATING.equal("PG-13"))
.count();
System.out.format("There are %d PG-13 films in the DB", count);
//这里的close()方法是个迷 我用的stop方法 好像也没得选
app.close();
}
输出结果
There are 223 PG-13 films in the DB
流实际上是描述结果的声明性语句(具有PG-13评级的电影),而不是关于要执行的操作和顺序的命令语句。因此,Speedment运行时可以自由地以它认为合适的任何方式计算所需的结果,而运行这段代码将导致数据库执行以下SQL查询。
官方的
SELECT COUNT(*) FROM sakia.film WHERE ('rating' = 'PG-13' COLLATE utf8_bin)
我控制台输出的
SELECT COUNT(*) FROM (SELECT `film_id`,`title`,`description`,`release_year`,`language_id`,`original_language_id`,`rental_duration`,`rental_rate`,`length`,`replacement_cost`,`rating`,`special_features`,`last_update` FROM `sakila`.`film` WHERE (`rating` = ? COLLATE utf8_bin)) AS A, values:[PG-13]
步骤5:通过主键查找基本胶片
虽然数据库中的项目计数可以通过Speedment完全委托给数据库引擎,但是一个典型的用例也需要在-JVM中进行数据操作。作为第一个例子,请考虑以下使用电影ID查找影片的代码。可以说,作为最基本的查找类型,完成此任务的代码非常简单;在ID上过滤电影流,然后将该流的电影映射到我们正在寻找的描述类型。
Scanner scn = new Scanner(System.in);
System.out.println("Please enter Film ID ");
final int id = Integer.decode(scn.nextLine().trim());
final Optional<String> title = films.stream()
.filter(Film.FILM_ID.equal(id)) // find the films we are looking for
.map(Film.TITLE) // switch from a stream of films to one of titles
.findAny(); // we want the first and only match for this unique key
if (title.isPresent()) {
System.out.format("Film ID %d has title %s.", id, title.get());
} else {
System.out.format("Film ID not found.", id);
}
app.close();
为了清晰起见,没有进行适当的输入验证。
步骤6:理解流优化
Speedment运行时框架处理Speedment流的执行,并且由于应用程序中的流是一个声明式构造,只要最终结果保持不变,Speedment运行时就可以以任何方式优化流。
作为这种优化的示例,请考虑以下代码片段:
long count = films.stream()
.filter(Film.RATING.equal("PG-13"))
.filter(Film.LENGTH.greaterOrEqual(75))
.map(Film.TITLE)
.sorted()
.count();
System.out.printf("Found %d films", count);
此流的结果是由两个不同谓词筛选的项的计数(就是那两个filter),这些项被映射到String并最终排序。读者可能会注意到,从电影到电影标题的映射以及电影标题的排序都不会影响流中项目的数量。Speedment运行时将得出相同的结论,并优化排序和映射操作,再次将所有工作留给数据库引擎,并按照以下路线进行数据库查询
SELECT COUNT(*) FROM 'sakila'.'film' WHERE ('rating' = 'PG-13' COLLATE utf8_bin) AND ('length' >= 75)
显然,当流构建为上面所述的单个语句序列时,只有当应用程序的设计人员创建了次优代码时,优化才会有所帮助。然而,非终止流是一个逻辑结构,可以作为参数传递,因此很有可能允许流结构的构造是分析输入数据的结果,只有在某些条件保持不变时才会添加某些部分。知道框架将在执行前优化流,它允许应用程序设计器关注功能正确性,而不是所有创建最佳流的执行路径。
上面这些我没太搞懂 ~ 大佬可以自行去官网看看 回头与我讨论
步骤7:电影分类
作为一个更详细的例子,下面的代码片段收集电影流并按分级对它们进行分组。这段代码演示了Speedment如何让任何数据库应用程序立即访问Java流的全部功能和功能。
films.stream()
.collect(Collectors.groupingBy(Film.RATING,
Collectors.counting())).forEach(
(rating, count) -> System.out.printf("There are %d %s rated films.%n", count, rating));
输出如下。
There are 223 PG-13 rated films.
There are 195 R rated films.
There are 210 NC-17 rated films.
There are 178 G rated films.
There are 194 PG-rated films.
步骤8:通过演员名称查找电影
对于SpeedmentStreams,一个稍微高级一些的用例是寻找具有给定姓氏的演员的电影。为了实现这一点,应用程序逻辑将被分成两部分。首先,我们计算selectedActorIds名字匹配的演员。然后,我们过滤有关角色ID中的电影和演员之间的关系,最后将流中的项映射为所需的输出格式。
FilmManager films = app.getOrThrow(FilmManager.class);
ActorManager actors = app.getOrThrow(ActorManager.class);
FilmActorManager filmActors = app.getOrThrow(FilmActorManager.class);
Scanner scn = new Scanner(System.in);
System.out.println("Please enter actor last name ");
final String actorName = scn.nextLine().trim();
Set<Integer> selectedActorIds = actors.stream()
.filter(Actor.LAST_NAME.equalIgnoreCase(actorName))
.mapToInt(Actor.ACTOR_ID) // turning the stream into a stream of actor IDs
.boxed() // turning IntStream into Stream<Integer>
.collect(toSet());
if (selectedActorIds.isEmpty()) {
System.out.println("No actor with last name " + actorName + " found.");
} else {
System.out.println("Films with actor with last name " + actorName + ":");
filmActors.stream()
.filter(FilmActor.ACTOR_ID.in(selectedActorIds))
.map(films.finderBy(FilmActor.FILM_ID)) // the stream of films we are looking for
.map(Film.TITLE.getter()) // the stream of film titles
.sorted()
.forEach(title -> System.out.println(" " + title));
}
示例输出
下面是应用程序输出的一个示例,其中我们查找了FileID 14,然后查找了一个演员名为Akroyd的电影。
Please enter Film ID
14
Film ID 14 has title ALICE FANTASIA
Please enter actor last name
Akroyd
Films with an actor with last name Akroyd:
APOLLO TEEN
BACKLASH UNDEFEATED
BETRAYED REAR
...
教程3-SpeedMent集成SpringBoot
在前面的教程中介绍了基本的Speedment代码生成和应用程序逻辑之后,本教程在这些知识的基础上展示了如何使用SpringBoot为Speedment应用程序创建RESTAPI。
步骤1:建立数据库
可以下载Sakila数据库这里。安装说明如下这里(依然用上面下载的那个)
步骤2:创建一个新的Maven项目
与前面的教程一样,创建一个新的Java 8 Maven项目和pom.xml-存档。对于本教程,我们还添加了SpringBoot框架依赖项。在下面,我们假设一个MySQL数据库,因为上面链接的Sakila数据库是MySQL。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>com.speedment</groupId>
<artifactId>speedment-maven-plugin</artifactId>
<version>3.2.5</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.speedment</groupId>
<artifactId>runtime</artifactId>
<version>3.2.5</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
</dependencies>
步骤3:Spring集成
基于Spring引导的应用程序的起点是SpringApplication.run方法。下面的主类是引导应用程序所需的全部内容。
@SpringBootApplication
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
SpringApplication.run(Main.class, args);
}
}
要向应用程序添加任何有意义的功能,我们首先创建RestController。使用Spring注释,我们声明了一个类,它将管理电影其余端点的服务器端。控制器定义四个不同的端点;
所有电影的列表(/),
按ID查找胶片(/{id}),
通过任何具有给定名称的演员进行电影查找(/byactor/{actorName}),
按演员名称分组的电影查找(/byactors/{actorName})并对演员名称部分进行筛选。
@RestController
@RequestMapping("/film")
public class FilmsController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final FilmActorManager filmActors;
private final ActorManager actors;
private final FilmManager films;
public FilmsController(SakilaApplication app) {
films = app.getOrThrow(FilmManager.class);
filmActors = app.getOrThrow(FilmActorManager.class);
actors = app.getOrThrow(ActorManager.class);
}
@GetMapping("")
List<Film> getFilms() {
return films.stream().collect(toList());
}
@GetMapping("{id}")
Film getFilmById(@PathVariable int id) {
return films.stream().filter(Film.FILM_ID.equal(id)).findAny().orElse(null);
}
@GetMapping("byactor/{actorName}")
List<Film> getFilmByActor(@PathVariable String actorName) {
Integer actorId = actors.stream()
.filter(Actor.LAST_NAME.equalIgnoreCase(actorName))
.mapToInt(Actor.ACTOR_ID)
.boxed()
.findAny()
.orElse(null);
return actorId == null ? emptyList() : filmActors.stream()
.filter(FilmActor.ACTOR_ID.equal(actorId))
.map(films.finderBy(FilmActor.FILM_ID))
.collect(toList());
}
@GetMapping("byactors/{actorName}")
Map<String, List<String>> getFilmByActors(@PathVariable String actorName) {
Set<Integer> actorIds = actors.stream()
.filter(Actor.LAST_NAME.containsIgnoreCase(actorName)
.or(Actor.FIRST_NAME.containsIgnoreCase(actorName)))
.mapToInt(Actor.ACTOR_ID)
.distinct()
.boxed()
.collect(toSet());
return actorIds.isEmpty() ? Collections.EMPTY_MAP : filmActors.stream()
.filter(FilmActor.ACTOR_ID.in(actorIds))
.collect(
groupingBy(actors.finderBy(FilmActor.ACTOR_ID)
.andThen(a -> a.getFirstName() + " " + a.getLastName()),
mapping(
films.finderBy(FilmActor.FILM_ID)
.andThen(GeneratedFilm::getTitle),
toList()
)
)
);
}
}
如控制器的构造函数所示,它依赖于实例化的SpeedmentSakilaApplication。在没有任何关于如何这样做的进一步说明的情况下,Spring框架将尝试在创建控制器之前实例化这样的对象。正如前面的教程所示,Speedment应用程序是使用构建器模式创建的,为了告诉Spring如何创建配置类。在Configuration类中,我们还提供了一个JSON格式构建器,当JSON编码上面的控制器类返回的数据结构时,Spring将使用它。应用程序在没有它的情况下可以工作,但是添加一个格式化程序允许我们自定义格式,对于本教程,我们需要缩进的JSON。
@Configuration
public class Setup {
@Bean
public SakilaApplication createApplication() {
return new SakilaApplicationBuilder()
.withBundle(MySqlBundle.class)
.withPassword("MyPassword")
.build();
}
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
return new Jackson2ObjectMapperBuilder().indentOutput(true);
}
}
有一个main-方法作为一个执行起点,一个控制器用于RESTAPI背后的逻辑,还有一个用于设置事物的配置类,所有这些都提供给Spring,以确定运行时依赖关系,并启动一个向客户端公开我们的API的HTTP服务器。
示例输出
查询单个胶片的ID可以如下所示。
curl http://localhost:8080/film/14
{
"filmId": 14,
"title": "ALICE FANTASIA",
"description": "A Emotional Drama of a A Shark And a Database Administrator who must Vanquish a Pioneer in Soviet Georgia",
"releaseYear": "2006-01-01",
"languageId": 1,
"originalLanguageId": null,
"rentalDuration": 6,
"rentalRate": 0.99,
"length": 94,
"replacementCost": 23.99,
"rating": "NC-17",
"specialFeatures": "Trailers,Deleted Scenes,Behind the Scenes",
"lastUpdate": 1139979822000
}
如果要求所有电影的主角都是一个姓鲍尔的演员,就会有一长串我们在这里简称的电影。grep 电影片名。
curl -s http://localhost:8080/film/byactor/ball | grep title
"title" : "ALONE TRIP",
"title" : "ANGELS LIFE",
"title" : "ANTITRUST TOMATOES",
"title" : "BALLOON HOMEWARD",
"title" : "BINGO TALENTED",
"title" : "BIRDCAGE CASPER",
"title" : "BRIGHT ENCOUNTERS",
"title" : "CABIN FLASH",
"title" : "CAT CONEHEADS",
"title" : "COMANCHEROS ENEMY",
"title" : "DESERT POSEIDON",
"title" : "DESPERATE TRAINSPOTTING",
"title" : "EXTRAORDINARY CONQUERER",
"title" : "GHOST GROUNDHOG",
"title" : "GREEDY ROOTS",
"title" : "HILLS NEIGHBORS",
"title" : "HOTEL HAPPINESS",
"title" : "HUNTER ALTER",
"title" : "JADE BUNCH",
"title" : "KING EVOLUTION",
"title" : "LOVERBOY ATTACKS",
"title" : "MAGNIFICENT CHITTY",
"title" : "MASK PEACH",
"title" : "NATURAL STOCK",
"title" : "NONE SPIKING",
"title" : "PATRIOT ROMAN",
"title" : "PERDITION FARGO",
"title" : "SCARFACE BANG",
"title" : "SENSE GREEK",
"title" : "TRAMP OTHERS",
"title" : "TROUBLE DATE",
"title" : "UNFAITHFUL KILL",
"title" : "WIND PHANTOM",
几个演员查找电影的输出比较简短,因此,例如,列出名为AykRod的演员的电影会产生以下结果:为了可读性,每个电影列表都被截断。
curl -s http://localhost:8080/film/byactors/Akroyd
{
"KIRSTEN AKROYD" : [ "BOULEVARD MOB", "BRAVEHEART HUMAN", "BUCKET BROTHERHOOD", ... ],
"DEBBIE AKROYD" : [ "APOLLO TEEN", "CLUB GRAFFITI", "FAMILY SWEET", ... ],
"CHRISTIAN AKROYD" : [ "BACKLASH UNDEFEATED", "BETRAYED REAR", "CAPER MOTIONS", ... ]
}
参考
- Java中函数式编程的谓词函数(Predicates)
https://blog.csdn.net/u010832551/article/details/74739933 - 成为 Java Stream 高手https://gitchat.csdn.net/activity/5db7cfc1a8131649a41b1f76?utm_source=chatAppChannel&spm=1002.2030.3001.4075#1createstreams
- speedment 官方文档
https://speedment.github.io/speedment-doc/tutorials.html#tutorial-1—hello-speedment
写在最后
SpeedMent是本人在学习Stream时发现的,非常好奇,于是查看相关文档并将相关操作过程记录于本文,但要说SpeedMent的具体开发步骤,上生产,还需进一步研究,而且该技术推广都不高,所以目前还是玩玩的心态来学,还可以拿来练习流的使用。
附:Stream 常见操作
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.toList;
import static sun.swing.MenuItemLayoutHelper.max;
/**
* @Auther: 洺润
* @Date: 2020/9/7
* @Description:
*/
public class StreamTest {
// public String[] str =
//开胃菜
@Test
public void m1() {
//筛选L开头的字符串 并进行排序
List<String> list = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.filter(s -> s.startsWith("L"))
.map(String::toUpperCase)
.sorted()
.collect(toList());
list.forEach(System.out::println);
}
@Test
public void m2() {
//intStream
IntStream intStream = IntStream.of(1, 2, 3);
IntStream intStream1 = IntStream.rangeClosed(1, 9); //产生[1,9]
IntStream iterate = IntStream.iterate(1, i -> i * 2);
IntStream chars = "ABC".chars();
IntStream ints = new Random().ints();
//数组转换为Stream
String[] strings = {"Monkey", "Lion", "Giraffe", "Lemur"};
Stream<String> strings1 = Stream.of(strings);
Stream<String> monkey = Stream.of("Monkey", "Lion", "Giraffe", "Lemur");
//集合转换为Stream
List<String> list = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur");
Stream<String> streamFromList = list.stream();
Set<String> set = new HashSet<>(list);
Stream<String> streamFromSet = set.stream();
//将文件中的每一行作为单独的元素保存
try {
List<String> strings2 = Files.lines(Paths.get("C:\\Users\\Administrator\\Desktop\\1.txt"))
.collect(toList());
// strings2.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
//中间操作
@Test
public void m3() {
//过滤操作 filter
IntStream stringStream = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.filter(s -> s.startsWith("L"))
.limit(2)//limit操作 实际上创建了一个新的stream
.skip(2)//跳过前两个
.distinct() //去重
.sorted() //排序
.sorted(Comparator.comparing(String::length)) //自定义排序
.map(String::toUpperCase) //做值的转换 能变成值的类型
.mapToInt(String::length); //转换为Int除此之外还有double long等
//压扁操作 FlatMap
// 从类型 T 到返回 R 的 Stream 的函数。函数将元素将其展平为 Stream,flatMap() 将 Stream 的所有元素串联在一起。
Stream<Character> chars = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur"
).flatMap(s -> s.chars().mapToObj(i -> (char) i));
}
/**
* 终端操作
* 在启动终端操作之前,Stream 将不会对源的元素执行任何计算。
* 这意味着仅在需要时才使用源元素,这是避免不必要工作的明智方法。
* 这也意味着一旦应用了终端操作,Stream 将被消耗,并且无法再添加其他操作。
*/
@Test
public void m4() {
//Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
// ForEach 和 ForEachOrdered 操作
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion").forEach(System.out::println);
// Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion").forEachOrdered(System.out::println);
/**
* 收集数据的操作 Collecting Elements
* Streams 的常见用法是构建元素的“存储桶” ,或更具体地说,构建包含特定元素集合的数据结构。
* 这可以通过在 Stream 的末尾调用终端操作 collect() 来完成,要求它将元素收集到给定的数据结构中
*/
Set<String> collect = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.collect(Collectors.toSet());
List<String> collect1 = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.collect(toList());
LinkedList<String> collect2 = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.collect(Collectors.toCollection(LinkedList::new));// 使用通用集合
//转换成数组
String[] strings = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.toArray(String[]::new);
//转换成map
Map<String, Integer> toMap = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.distinct()
.collect(Collectors.toMap(
Function.identity(), //Function<String, K> keyMapper
s -> (int) s.chars().distinct().count()// Function<String, V> valueMapper
));
//使用 GroupingBy 来收集结果 groupingByList: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
Map<Character, List<String>> groupingByList = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
s -> s.charAt(0) // Function<String, K> classifier
));
// 使用带有下游收集器的 GroupingBy 来收集结果 groupingByCounting: {G=1, L=3, M=1}
Map<Character, Long> groupingByCounting = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
s -> s.charAt(0), // Function<String, K> classifier
counting() // Downstream collectorFco
));
//判断元素是否存在
boolean b1 = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
//计算操作
long nrOfAnimals = Stream.of(
"Monkey", "Lion", "Giraffe", "Lemur"
).count(); //能够得到动物的数量
int sum = IntStream.of(1,2,3).sum();//6
//计算平均值
OptionalDouble average = IntStream.of(1, 2, 3).average();
//找到最大值
int i = IntStream.of(1, 2, 3).max().orElse(0);
//将结果进行合并 statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
}
}