s+=1 和 s=s+1看了这篇,你会明白好多自己不知道的(对小白)

本文详细讲解了在Java中`s+=1`和`s=s+1`的区别,涉及类型隐式转换、短整型溢出和常量池优化,同时探讨了错误案例和正确用法。重点在于理解类型转换规则及避免潜在问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

s+=1和s=s+1区别

  • 下面的代码会报错,知道为什么么?
	short s = 1;
    s = s + 1;

因为:1是int型,s+1会自动将s转化为int型进行运算,结果就是int型,

果将int直接赋值给short会报错,高到第的转化需要强转.

  • 正确的写成下面这样
		//注意加两个括号
		short s = 1;
        s = (short) (s + 1);
  • 如果改成这样会对么?
    short s = 1;
    s = s + (short)1;
  • 告诉你这样也是错的,为什么呢?(记住就行)
  1. JAVA中short和short相加自动转化为int
  2. 精度小于int的数值运算的时候都回被自动转换为int后进行计算
  • 下面的也可以,那么问题来了,这个为啥这样可以?
//这样也可以实现s加1;更为简单 	
short s = 1;
        s+=1;
  1. s += 1是等价于 s = (s的数据类型)(s + 1)
  2. 对于+= -=,*=等系统会自动执行类型转换操作
  3. 更深层次涉及到jvm如何实现(实话说我还不够格,以后回来补上的)
  • 下面的代码不报错,这不是int转short么,为什么?
short s = 1 + 2;
  1. 因为你要知道常量池优化:在给变量进行赋值的时候,如果左边全是常量,没有任何变量的时候,那么java的编译器会直接计算右边的结果,然后赋值给左边变量,相当于short s=3;如果常量运算的值超过范围就会报编译错误.

可以看看这个链接,写的非常明白

  • 想要再深入细节的可以自己搜,后期会把虚拟机实现方式补下.
import org.apache.log4j.{Level, Logger} import org.apache.spark.SparkConf import org.apache.spark.sql.functions._ import org.apache.spark.sql.{DataFrame, SparkSession} import java.sql.Timestamp import java.text.SimpleDateFormat import java.util.Calendar object prac1 { def main(args: Array[String]): Unit = { System.setProperty("HADOOP_USER_NAME","root") Logger.getLogger("org").setLevel(Level.ERROR) val sparkConf = new SparkConf().setMaster("local[*]").setAppName("task1") val spark = new SparkSession.Builder().config(sparkConf) .config("spark.sql.warehouse.dir", "hdfs://node1:8020/user/hive/warehouse") .config("spark.sql.shuffle.partitions", "1500") .config("dfs.replications", "3") .config("hive.exec.dynamic.partition.mode", "nonstrict") .config("hive.exec.max.dynamic.partitions", "3000") .enableHiveSupport() .getOrCreate() val table=Array("customer_inf","product_info","order_master","order_detail") table.foreach(x=>{ println(s"===================抽取数据:$x=====================") val mysql = new Tools().loadMysql(spark, x).cache() mysql.show() println("====================获取增量字段=====================") var incre: Any = null val simple = new SimpleDateFormat("yyyyMMdd") val calendar=Calendar.getInstance() calendar.add(Calendar.DATE,-1) val etl_date = simple.format(calendar.getTime) val simple1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") if (x=="customer_inf"){ incre = spark.table(s"ods.customer_inf").select(max("modified_time")).collect()(0).get(0) if (incre==null){ incre=Timestamp.valueOf(simple1.parse("0").getTime.toString) } } else { incre = spark.table(s"ods.$x").select(max("modified_time")).collect()(0).get(0) if (incre==null){ incre=Timestamp.valueOf(simple1.parse("0").getTime.toString) } } println(s"======================Final incre:$incre=======================") mysql.where(col("modified_time")>incre) .withColumn("etl_date",lit(etl_date).cast("string")) // .show() .write.format("hive").mode("append").partitionBy("etl_date").saveAsTable(s"ods.$x") }) spark.close() } } class Tools { def loadMysql(spark:SparkSession,table:String): DataFrame ={ val prop=Map( "url"->"jdbc:mysql://node1/ds_db01?useSSL=false", "driver"->"com.mysql.jdbc.Driver", "user"->"root", "password"->"8888", "dbtable"->table ) spark.read.format("jdbc") .options(prop) .load() } }用这里小白我该怎么写这个代码,还有怎么记
03-16
<think>嗯,用户让我解释这段Scala代码,并且作为一个小白该怎么写记住它。首先,我需要理解代码的整体结构。看起来这是一个Spark程序,用于从MySQL抽取数据到Hive的ODS层。用户可能对Spark数据处理流程太熟悉,所以得从基础开始解释。 代码开头导入了很多库,比如Log4j、SparkConf、SparkSession等。这部分可能需要解释每个导入的作用,但用户是小白,可能需要先概述这些库的用途,而是逐个详细说明。然后定义了一个对象prac1,里面有main方法,这是Scala程序的入口点。 接下来,System.setProperty设置了Hadoop用户,Logger.getLogger用来调整日志级别,避免过多的日志干扰。然后配置SparkConf,设置本地模式应用名称,接着创建SparkSession,配置Hive相关的参数,比如warehouse目录、分区数、副本数等。这部分涉及到SparkHive的集成,用户可能需要了解SparkSession的作用以及Hive的配置项。 然后定义了一个表名数组,循环处理每个表。在循环里,用Tools类从MySQL读取数据,缓存并展示。接着处理增量字段,获取前一天的日期作为ETL日期。这里使用了SimpleDateFormatCalendar,可能需要解释时间处理的部分。然后根据表名同,处理增量时间戳,如果是customer_inf表,则从ODS层取最大modified_time,否则从其他表取。如果incre是null,就设置为初始时间。这可能涉及到增量抽取的逻辑,用户需要明白如何获取增量数据。 之后用where过滤出modified_time大于incre的数据,添加etl_date分区字段,写入Hive表。这里需要解释DataFrame的写入操作,分区的作用,以及mode("append")的意义。最后关闭SparkSession。 Tools类中的loadMysql方法,使用JDBC连接MySQL,读取数据。需要解释JDBC配置参数,比如URL、驱动、用户密码等。 用户可能需要知道整个流程的步骤:配置环境、读取MySQL数据、处理增量、写入Hive。以及如何逐步构建这个代码,比如先配置Spark,再处理数据抽取,最后处理增量逻辑。可能需要分步骤讲解,每个部分的作用编写方法。 关于记忆方法,可以建议用户将代码分为几个模块:配置部分、数据抽取循环、增量逻辑、写入操作。每个模块单独理解,再组合起来。同时,强调增量同步的关键点,比如获取最大时间戳,过滤新增数据,分区写入。可能还需要提醒常见问题,比如时间格式处理、空值处理、分区字段添加等。 用户可能对SparkHive的配置太熟悉,需要解释这些配置项的意义,比如shuffle分区数、副本数、动态分区设置。此外,可能需要提到依赖管理,比如确保正确的JDBC驱动Spark版本兼容。 最后,建议用户通过实际运行调试来加深理解,比如打印中间结果,查看日志,逐步验证每个部分的功能。同时,可以推荐学习资源,如Spark SQL文档、Scala基础、ETL最佳实践等,帮助用户巩固知识。</think>好的,我会分步骤帮你理解这个代码的结构功能,并提供记忆方法: 一、代码结构分解(按执行顺序) 1. 环境准备部分 ```scala // 设置Hadoop用户身份(对接HDFS时需要) System.setProperty("HADOOP_USER_NAME","root") // 设置日志级别(避免过多日志干扰) Logger.getLogger("org").setLevel(Level.ERROR) // 创建Spark配置 val sparkConf = new SparkConf() .setMaster("local[*]") // 本地模式运行 .setAppName("task1") // 应用名称 // 创建SparkSession(访问Hive的核心入口) val spark = SparkSession.builder() .config(sparkConf) .config("spark.sql.warehouse.dir", "hdfs://node1:8020/user/hive/warehouse") .config("spark.sql.shuffle.partitions", "1500") // shuffle分区数 .config("dfs.replications", "3") // HDFS副本数 .config("hive.exec.dynamic.partition.mode", "nonstrict") // 动态分区模式 .enableHiveSupport() // 启用Hive支持 .getOrCreate() ``` 2. 表定义与循环处理 ```scala // 需要处理的表列表 val table = Array("customer_inf","product_info","order_master","order_detail") // 遍历每张表进行数据同步 table.foreach { x => // 这里处理每张表的逻辑... } ``` 3. 增量同步核心逻辑 ```scala // 获取当前日期(用于分区字段) val calendar = Calendar.getInstance() calendar.add(Calendar.DATE, -1) // 取昨天日期 val etl_date = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime) // 获取最大修改时间(增量标记) var incre = spark.table(s"ods.$x") .select(max("modified_time")) // 从Hive表获取最新时间 .collect()(0).get(0) // 处理首次同步的情况(没有历史数据时) if (incre == null) { incre = new Timestamp(0) // 1970-01-01 00:00:00 } // 过滤增量数据并写入Hive mysql.where(col("modified_time") > incre) .withColumn("etl_date", lit(etl_date)) // 添加分区字段 .write .format("hive") .mode("append") // 追加模式 .partitionBy("etl_date") // 按日期分区 .saveAsTable(s"ods.$x") ``` 二、代码功能总结 这是一个基于Spark的增量数据同步程序,主要完成: 1. 从MySQL数据库抽取数据 2. 按modified_time字段识别增量数据 3. 将增量数据写入Hive的ODS层(按日期分区) 4. 支持多表批量处理 三、记忆技巧 1. 分层记忆法: - 环境配置层(Spark+Hive配置) - 数据抽取层(MySQL连接) - 增量处理层(时间戳比对) - 数据存储层(Hive写入) 2. 关键配置记忆点: - `enableHiveSupport`:启用Hive集成 - `dynamic.partition.mode=nonstrict`:动态分区模式 - `shuffle.partitions=1500`:调整并行度 3. 增量逻辑口诀: - "查Hive取最新,比时间筛增量" - "首次全量用零点,后续增量比时间" 四、小白学习路径建议 1. 先理解基础组件: - Spark SQL:`spark.read.format("jdbc")` - Hive集成:`saveAsTable`写入 - 时间处理:`SimpleDateFormat`用法 2. 再掌握增量逻辑: - 通过`modified_time`字段判断新增/更新 - 使用`max()`函数获取最新时间点 - `etl_date`分区字段的作用 3. 最后理解配置参数: - `local[*]`:本地模式运行 - `shuffle.partitions`:调整任务并行度 - `dfs.replications`:HDFS副本数量 五、常见问题提醒 1. 驱动问题:确保mysql-connector-java.jar在classpath中 2. 时间格式:SimpleDateFormat的线程安全问题(当前写法在Spark中是安全的) 3. 空值处理:`incre == null`的判断必须放在Driver端(collect后判断) 4. 分区写入:Hive表必须预先创建好分区字段对应的表结构 建议通过画流程图来辅助记忆(数据流向:MySQL -> Spark -> Hive),并实际运行调试观察每个阶段的输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值