Flink04: Flink核心API之DataStream

news/2024/3/29 16:55:48/文章来源:https://blog.csdn.net/anglemanyi/article/details/129115293

一、Flink 4种不同层次的API

 

Flink中提供了4种不同层次的API,每种API在简洁和易表达之间有自己的权衡,适用于不同的场景。目前上面3个会用得比较多。
        • 低级API(Stateful Stream Processing):提供了对时间和状态的细粒度控制,简洁性和易用性较差,主要应用在一些复杂事件处理逻辑上。
        • 核心API(DataStream/DataSet API):主要提供了针对流数据和批数据的处理,是对低级API进行了一些封装,提供了filter、sum、max、min等高级函数,简单易用,所以这些API在工作中应用还是比较
广泛的。
        • Table API:一般与DataSet或者DataStream紧密关联,可以通过一个DataSet或DataStream创建出一个Table,然后再使用类似于filter, join,或者 select这种操作。最后还可以将一个Table对象转成DataSet或DataStream。
        • SQL:Flink的SQL底层是基于Apache Calcite,Apache Calcite实现了标准的SQL,使用起来比其他API更加灵活,因为可以直接使用SQL语句。Table API和SQL可以很容易地结合在一块使用,因为它们都返回Table对象。

        针对这些API我们主要学习下面这些 

 二、DataStream API

DataStream API主要分为3块:DataSource、Transformation、DataSink。

  • DataSource是程序的输入数据源。
  • Transformation是具体的操作,它对一个或多个输入数据源进行计算处理,例如map、flatMap和filter等操作。
  • DataSink是程序的输出,它可以把Transformation处理之后的数据输出到指定的存储介质中。

 (一)DataStream API之DataSoure

        DataSource是程序的输入数据源,Flink提供了大量内置的DataSource,也支持自定义DataSource,不过目前Flink提供的这些已经足够我们正常使用了。
        Flink提供的内置输入数据源:包括基于socket、基于Collection,还有就是Flink还提供了一批Connectors,可以实现读取第三方数据源,

说明:

        (1)Flink 内置:表示Flink中默认自带的。
        (2)Apache Bahir:表示需要添加这个依赖包之后才能使用的。
        (3)针对source的这些Connector,我们在实际工作中最常用的就是Kafka
        (4)当程序出现错误的时候,Flink的容错机制能恢复并继续运行程序,这种错误包括机器故障、网络故障、程序故障等
        (5)针对Flink提供的常用数据源接口,如果程序开启了checkpoint快照机制,Flink可以提供这些容错性保证

1. 使用集合创建DataStream(scala代码)

package com.imooc.scala.streamimport org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}object StreamCollectionSourceScala {def main(args: Array[String]): Unit = {val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironmentimport org.apache.flink.api.scala._//使用collection集合生成DataStreamval text: DataStream[Int] = env.fromCollection(Array(1, 2, 3, 4, 5))text.print().setParallelism(1)env.execute("StreamCollectionSourceScala")}
}

2. 使用集合创建DataStream (java代码)

package com.imooc.java.stream;import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;import java.util.Arrays;public class StreamCollectionSourceJava {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();//使用Collection集合生成DataStreamDataStreamSource<Integer> text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5));text.print().setParallelism(1);env.execute("StreamCollectionSourceJava");}
}

(二)、DataStream API之Transformation

transformation是Flink程序的计算算子,负责对数据进行处理,Flink提供了大量的算子,其实Flink中的大部分算子的使用和spark中算子的使用是一样的,下面我们来看一下:

 

 1. union 

  • 表示合并多个流,但是多个流的数据类型必须一致,多个流join之后,就变成了一个流。
  • 应用场景:多种数据源的数据类型一致,数据处理规则也一致

 scala代码:

package com.imooc.scala.streamimport org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}/*** 合并多个流,多个流的数据类型必须一致* 应用场景:多种数据源的数据类型一致,数据处理规则也一致**/
object StreamUnionScala {def main(args: Array[String]): Unit = {val env = StreamExecutionEnvironment.getExecutionEnvironmentimport org.apache.flink.api.scala._//第一份数据流val text1: DataStream[Int] = env.fromCollection(Array(1, 2, 3, 4, 5))//第二份数据流val text2: DataStream[Int] = env.fromCollection(Array(6, 7, 8, 9, 10))//合并流val unionStream: DataStream[Int] = text1.union(text2)//打印流中的数据unionStream.print().setParallelism(1)env.execute("StreamUnionScala")}
}

Java代码

package com.imooc.java.stream;import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;import java.util.Arrays;public class StreamUnionJava {public static void main(String[] args) throws Exception{StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();//第一份数据流DataStreamSource<Integer> text1 = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5));//第二份数据流DataStreamSource<Integer> text2 = env.fromCollection(Arrays.asList(6, 7, 8, 9, 10));//合并流DataStream<Integer> unionStream = text1.union(text2);//打印unionStream.print().setParallelism(1);env.execute("StreamUnionJava");}
}

2. connect:只能连接两个流,两个流的数据类型可以不同

        两个流被connect之后,只是被放到了同一个流中,它们内部依然保持各自的数据和形式不发生任何变化,两个流相互独立。

        connect方法会返回connectedStream,在connectedStream中需要使用CoMap、CoFlatMap这种函数,类似于map和flatmap。

Scala代码:

package com.imooc.scala.streamimport org.apache.flink.streaming.api.functions.co.CoMapFunction
import org.apache.flink.streaming.api.scala.{ConnectedStreams, DataStream, StreamExecutionEnvironment}/*** 只能连接两个流,两个流的数据类型可以不同* 应用:可以将两种不同格式的数据统一成一种格式**/
object StreamConnectScala {def main(args: Array[String]): Unit = {val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironmentimport org.apache.flink.api.scala._val text1: DataStream[String] = env.fromElements("user:tom,age:18")val text2: DataStream[String] = env.fromElements("user:tom_age:18")//连接两个流val connectStream: ConnectedStreams[String, String] = text1.connect(text2)val text: DataStream[String] = connectStream.map(new CoMapFunction[String, String, String] {override def map1(in1: String): String = {in1.replace(",", "-")}override def map2(in2: String): String = {in2.replace("_", "-")}})//打印text.print().setParallelism(1)//env.execute("StreamConnectScala")}
}

Java代码:

package com.imooc.java.stream;import org.apache.flink.streaming.api.datastream.ConnectedStreams;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.CoMapFunction;import java.awt.event.TextEvent;/*** 只能连接两个流,两个流的数据类型可以不同* 应用:可以将两种不同格式的数据统一成一种格式**/
public class StreamConnectJava {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();//第1份数据流DataStreamSource<String> text1 = env.fromElements("user:tom,age:18");//第2份数据流DataStreamSource<String> text2 = env.fromElements("user:tom_age:18");//合并两个流ConnectedStreams<String, String> connectStream = text1.connect(text2);SingleOutputStreamOperator<Object> text = connectStream.map(new CoMapFunction<String, String, Object>() {@Overridepublic Object map1(String s) throws Exception {return s.replace(",", "-");}@Overridepublic Object map2(String s) throws Exception {return s.replace("_", "-");}});text.print().setParallelism(1);env.execute("StreamConnectJava");}
}

3.split:根据规则把一个数据流切分为多个流

注意:

(1)split只能分一次流,切分出来的流不能继续分流

(2)split需要和select配合使用,选择切分后的流

Scala代码:

package com.imooc.scala.streamimport java.{lang, util}import org.apache.flink.streaming.api.collector.selector.OutputSelector
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment/*** 根据规则把一个数据流切分为多个流* 注意:split只能分一次流,切分出来的流不能继续分流* split需要和select配合使用,选择切分后的流* 应用场景:将一份数据流切分为多份,便于针对每一份数据使用不同的处理逻辑*/
object StreamSplitScala {def main(args: Array[String]): Unit = {val env = StreamExecutionEnvironment.getExecutionEnvironmentimport org.apache.flink.api.scala._val text = env.fromCollection(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))//按照数据的奇偶性对数据进行分流val splitStream = text.split(new OutputSelector[Int] {override def select(value: Int): lang.Iterable[String] = {val list = new util.ArrayList[String]()if (value % 2 == 0) {list.add("even") // 偶数} else {list.add("odd") //奇数}list}})//选择流val evenStream = splitStream.select("even")evenStream.print().setParallelism(1)val oddStream = splitStream.select("odd")oddStream.print().setParallelism(1)env.execute("StreamSplitScala")}
}

 Java代码:

package com.imooc.java.stream;import org.apache.flink.streaming.api.collector.selector.OutputSelector;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SplitStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;import java.util.ArrayList;
import java.util.Arrays;public class StreamSplitJava {public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();DataStreamSource<Integer> text = env.fromCollection(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));SplitStream<Integer> splitStream = text.split(new OutputSelector<Integer>() {@Overridepublic Iterable<String> select(Integer value) {ArrayList<String> list = new ArrayList<>();if (value % 2 == 0) {list.add("even");} else {list.add("odd");}return list;}});DataStream<Integer> evenStream = splitStream.select("even");evenStream.print().setParallelism(1);DataStream<Integer> oddStream = splitStream.select("odd");oddStream.print().setParallelism(1);env.execute("StreamSplitJava");}
}

目前split切分的流无法进行二次切分,并且split方法已经标记为过时了,官方不推荐使用,现在官方推荐使用side output的方式实现。
下面我来看一下使用side output如何实现流的多次切分

Scala代码:

package com.imooc.scala.streamimport java.{lang, util}import org.apache.flink.streaming.api.collector.selector.OutputSelector
import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala.{OutputTag, StreamExecutionEnvironment}
import org.apache.flink.util.Collector/*** 根据规则把一个数据流切分为多个流* 注意:split只能分一次流,切分出来的流不能继续分流* split需要和select配合使用,选择切分后的流* 应用场景:将一份数据流切分为多份,便于针对每一份数据使用不同的处理逻辑*/
object StreamSplit2Scala {def main(args: Array[String]): Unit = {val env = StreamExecutionEnvironment.getExecutionEnvironmentimport org.apache.flink.api.scala._val text = env.fromCollection(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))//按照数据的奇偶性对数据进行分流//首先定义两个sideoutput来准备保存切分出来的数据val outputTag1 = new OutputTag[Int]("even")val outputTag2 = new OutputTag[Int]("odd")//注意: process属于Flink中的低级apival outputStream = text.process(new ProcessFunction[Int, Int] {override def processElement(value: Int, context: ProcessFunction[Int, Int]#Context, collector: Collector[Int]): Unit = {if (value % 2 == 0) {context.output(outputTag1, value)} else {context.output(outputTag2, value)}}})val evenStream = outputStream.getSideOutput(outputTag1)val oddStream = outputStream.getSideOutput(outputTag2)
//    evenStream.print().setParallelism(1)//对evenStream流进行二次切分val outputTag11 = new OutputTag[Int]("low") //保留小于等于5的数字val outputTag12 = new OutputTag[Int]("high") //保留大于5的数字val subOutputStream = evenStream.process(new ProcessFunction[Int, Int] {override def processElement(value: Int, context: ProcessFunction[Int, Int]#Context, collector: Collector[Int]): Unit = {if (value <= 5) {context.output(outputTag11, value)} else {context.output(outputTag12, value)}}})//获取小于等于5的数据流val lowStream = subOutputStream.getSideOutput(outputTag11)//获取大于5的数据流val highStream = subOutputStream.getSideOutput(outputTag12)lowStream.print().setParallelism(1)env.execute("StreamSplitScala")}
}

4. union和connect的区别

 

 

区别

        (1)union可以连接多个流,最后汇总成一个流,流里面的数据使用相同的计算规则

        (2)connect值可以连接2个流,最后汇总成一个流,但是流里面的两份数据相互还是独立的,每一份数据使用一个计算规则

5. split与side output区别

区别:

        (1)如果是只需要切分一次的话使用split或者side output都可以
        (2)如果想要切分多次,就不能使用split了,需要使用side output

 6. 分区相关的算子

 (三)、DataStream API之DataSink

        DataSink是 输出组件,负责把计算好的数据输出到其它存储介质中
        Flink支持把流数据输出到文件中,不过在实际工作中这种场景不多,因为流数据处理之后一般会存储到一些消息队列里面,或者数据库里面,很少会保存到文件中的。

        还有就是print,直接打印,这个其实我们已经用了很多次了,这种用法主要是在测试的时候使用的,方便查看输出的结果信息

1. Flink提供了一批Connectors,可以实现输出到第三方目的地

2. 针对sink的这些connector,我们在实际工作中最常用的是kafka、redis,针对Flink提供的常用sink组件,可以提供这些容错性保证

3. 需求:接收Socket传输过来的数据,把数据保存到Redis的list队列中。

Scala代码:

package com.imooc.scala.sinkimport org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.connectors.redis.RedisSink
import org.apache.flink.streaming.connectors.redis.common.config.FlinkJedisPoolConfig
import org.apache.flink.streaming.connectors.redis.common.mapper.{RedisCommand, RedisCommandDescription, RedisMapper}object StreamRedisSinkScala {def main(args: Array[String]): Unit = {val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment//连接socket获取输入数据val text: DataStream[String] = env.socketTextStream("bigdata01", 9001)import org.apache.flink.api.scala._val listData: DataStream[(String, String)] = text.map(word => ("l_words_scana", word))//指定redisSinkval conf: FlinkJedisPoolConfig = new FlinkJedisPoolConfig.Builder().setHost("bigdata01").setPort(6379).build()val redisSink = new RedisSink[Tuple2[String, String]](conf, new MyReidsMapper)listData.addSink(redisSink)env.execute("StreamRedisSinkScala")}}class MyReidsMapper extends RedisMapper[Tuple2[String, String]]{override def getCommandDescription: RedisCommandDescription = {new RedisCommandDescription(RedisCommand.LPUSH)}override def getKeyFromData(t: (String, String)): String = {t._1}override def getValueFromData(t: (String, String)): String = {t._2}
}

注意:执行代码之前,需要先开启socket和redis服务

 

 

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

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

相关文章

Endless lseek导致的SQL异常

最近碰到同事咨询的一个问题&#xff0c;在执行一个函数时&#xff0c;发现会一直卡在那里。 strace抓了下发现会话一直在执行lseek&#xff0c;大致情况如下&#xff1a; 16:13:55.451832 lseek(33, 0, SEEK_END) 1368064 <0.000037> 16:13:55.477216 lseek(33, 0, SE…

linux下安装mongoDB

一、下载mongoDB包 下载地址&#xff1a; https://www.mongodb.com/try/download/community 个人建议&#xff1a;如果是学习阶段&#xff0c;使用5以下版本更好些。 二、安装及配置 1、安装 # 1、解压 $ tar -zxvf mongodb-linux-x86_64-rhel70-4.4.19-rc1.tgz# 2、迁移目…

【音视频处理】为什么MP3不是无损音乐?音频参数详解,码率、采样率、音频帧、位深度、声道、编码格式的关系

大家好&#xff0c;欢迎来到停止重构的频道。上期我们讨论了视频的相关概念&#xff0c;本期我们讨论音频的相关概念。包括采样率、码率、单双声道、音频帧、编码格式等概念。这里先抛出一个关于无损音频的问题。为什么48KHz采样率的.mp3不是无损音乐 &#xff0c;而48KHz采样率…

高性能爬虫之单线程、多进程、多线程的使用,线程池、进程池、协程池的使用

目录一、单线程爬虫代码实现二、 多线程爬虫1、多线程的方法使用2、队列模块的使用3、多线程实现思路剖析4、代码实现**注意点&#xff1a;**三、多进程爬虫1、多进程程的方法使用2、多进程中队列的使用3 代码实现**小结**四、线程池实现爬虫1、线程池使用方法介绍2、使用线程池…

365天深度学习训练营-第J3周:DenseNet算法实战与解析

目录 一、前言 二、论文解读 1、DenseNet的优势 2、设计理念 3、网络结构 4、与其他算法进行对比 三、代码复现 1、使用Pytorch实现DenseNet 2、使用Tensorflow实现DenseNet网络 四、分析总结 一、前言 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习…

基于OSG的虚拟校园系统的设计与实现

基于open scene graph的虚拟校园系统的设计与实现 摘要 •引言 • OSG基本原理 •OSG操作与动画 •视点的定位和切换 •自由漫游 •路径漫游 • 路径动画 • 点选和文字 • 粒子系统 • 3DMAX • 无线通信与数据库设计 • 实现步骤 • 结论 摘要 随着科技的不断发展,人工智能&a…

DO-254 和 DO-178B的区别(文末有易灵思核心板及配套下载线)

DO-178B介绍 DO-178B&#xff0c;机载系统和设备认证中的软件考虑&#xff0c;在电子硬件被要求符合 DO-254 之前多年就已发布和采纳。DO-178B 的先行一步对电子硬件开发带来两个特别的后果。首先&#xff0c;使得硬件制造商有了一种倾向&#xff0c;为了避免 DO-178B 对软件开…

【MySQL】sql中explain解释和应用

这里写目录标题学习原因MySQL中explain的使用和用法解释explain的使用explain 运行结果的意义文字展示表格展示参考资料&#xff1a;结束语学习原因 在对sql的优化过程中使用了explain对指定的sql进行查看它的运行效果&#xff0c;以便找出sql的性能特点并进行优化 MySQL中ex…

Linux - POSIX信号量,基于环形队列的生产者消费者模型

信号量在Linux下&#xff0c;POSIX信号量是一种线程同步机制&#xff0c;用于控制多个线程之间的访问顺序。POSIX信号量可以用于实现线程之间的互斥或者同步。在之前的阻塞队列生产者消费者模型中&#xff0c;阻塞队列是一个共享资源&#xff0c;不管是生产者还是消费者&#x…

Mysql实战之日志系统:一条SQL更新语句是如何执行的

1.前言 上一篇咱们了解了MySQL 的执行过程&#xff0c;其中设计连接器、分析器、优化器、执行器和存储引擎&#xff0c;接下来我将给大家讲解一下在MySQL中一条更新语句是如何执行。我相信大家可能听公司的DBA提起过&#xff0c;可以将数据恢复到半个月内任意时间的状态&#…

Scala集合详解(第七章:集合、数组、列表、set集合、map集合、元组、队列、并行)(尚硅谷笔记)

集合第七章:集合7.1 集合简介7.1.1 不可变集合继承图7.1.2 可变集合继承图7.2 数组7.2.1 不可变数组7.2.2 可变数组7.2.3 不可变数组与可变数组的转换7.2.4 多维数组7.3 列表 List7.3.1 不可变 List7.3.2 可变 ListBuffer7.4 Set 集合7.4.1 不可变 Set7.4.2 可变 mutable.Set7.…

Android system实战 — Android R(11) 进程保活白名单

Android system实战 — Android R 进程保活白名单0. 前言1. 具体实现1.1 准备工作1.2 源码实现1.2.1 源码1.2.2 diff文件0. 前言 最近在Android R上实现一些需求&#xff0c;进行记录一下&#xff0c;关于进程保活的基础知识可以参考Android system — 进程生命周期与ADJ&#…

自动驾驶路径规划概况

文章目录前言介绍1. 路径规划在自动驾驶系统架构中的位置2. 全局路径规划的分类2.1 基础图搜索算法2.1.1 Dijkstra算法2.1.2 双向搜索算法2.1.3 Floyd算法2.2 启发式算法2.2.1 A*算法2.2.2 D*算法2.3 基于概率采样的算法2.3.1 概率路线图&#xff08;PRM&#xff09;2.3.2 快速…

蓝牙运动耳机什么牌子的好、运动蓝牙耳机排行榜推荐

近些年&#xff0c;户外运动兴起&#xff0c;运动耳机迎来爆发增长&#xff0c;拒绝运动乏味&#xff0c;追求健康运动方式&#xff0c;已经成为当下年轻人的共同诉求。跑步骑行听音乐&#xff0c;已经是运动爱好者再熟悉不过的操作&#xff0c;很多人在运动中离不开音乐的节奏…

代码随想录算法训练营第七天 | 454.四数相加II 、 383. 赎金信、15. 三数之和、18. 四数之和 、总结

打卡第七天&#xff0c;还是哈希表。 今日任务 454.四数相加II383.赎金信15.三数之和18.四数之和总结 454.四数相加II 代码随想录 class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, ve…

【vue2每日小知识】实现directive自定义指令的封装与全局注册

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;将我们的自定义指令directive统一管理并批量注册 目录 一、directive自定义指令介绍 二…

DS期末复习卷(六)

一、选择题(30分) 1&#xff0e; 设一组权值集合W{2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6}&#xff0c;则由该权值集合构造的哈夫曼树中带权路径长度之和为&#xff08; D &#xff09;。 (A) 20 (B) 30 (C ) 40 (D) 45 W(23)*3(456)*245 2&#xff0e;执行一…

Python、Java、JavaScript、C、Go等编程语言如何实现“定时器”功能

这是CSDN平台2月推出的一个活动(活动链接为&#xff1a;CSDN 征文活动)&#xff0c;聊聊时间的话题&#xff0c;小编我也不知道有什么好聊的时间的话题&#xff0c;看了CSDN给出的部分话题上&#xff0c;有一个这样的话题&#xff0c;如何用各种编程语言实现“定时器”&#xf…

GUI可视化应用开发及Python实现

0 建议学时 4学时&#xff0c;在机房进行 1 开发环境安装及配置 1.1 编程环境 安装PyCharm-community-2019.3.3 安装PyQt5 pip install PyQt5-tools -i https://pypi.douban.com/simple pip3 install PyQt5designer -i https://pypi.douban.com/simple1.2 环境配置 选择“…

JVM13命令行

2. JVM 监控及诊断工具-命令行篇 2.1. 概述 简单命令行工具 在我们刚接触 java 学习的时候&#xff0c;大家肯定最先了解的两个命令就是 javac&#xff0c;java&#xff0c;那么除此之外&#xff0c;还有没有其他的命令可以供我们使用呢&#xff1f; 我们进入到安装 jdk 的…