那些年我踩过的坑——Java

本文深入探讨Java中的构造器复用、接口使用、类加载过程、集合操作、异常处理等核心概念,同时涵盖并发编程、泛型应用及多线程同步等高级特性。

Java基础

  • 复用构造器:只能在构造函数第一行调用其他构造函数,且只能调用一个
  • 接口适合用来实现mixin(将一个类变量完全复制到另一个类中)
  • 类被load时,static初始化->内存申请->默认初始化->调用构造器
  • Arrays类用来对数组进行操作,Collections对Collection
  • Map中的key需要有equals方法,HashMap要有hashCode,TreeMap要实现Comparable
  • RuntimeException不需声明就能抛出
  • Input(Output)Stream是字节流,Reader/Writer是字符流
  • 一旦出现Foo.class,classloader已经把Foo的二进制读到了内存中,可能会出现内存占用问题,所以框架多存className,然后用反射loadclass
  • Java的泛型会根据赋值进行类型参数推断,但是返回结果被直接作为方法参数时不会进行类型参数推断。可以显示说明类型,形如:bar(Class.<Type>foo()),奇葩语法
  • 泛型可以使用自限定类型,实现类的泛型参数就是自己class Foo<T extends Foo<T>>,此时,可以声明一些参数为T的函数,只接受与自己相同类型的参数,例如Compare时,即jdk5以后支持的参数协变
  • ConcurrentHashMap只是给put与对象hash相同的对象链表加锁,速度会快,完全依赖会有问题
  • Exception是函数声明的一部分,所以,Runnable是不能throw一般的Exception的,只能throw RuntimeException。对于Thread中的Exception,使用UncaughtExceptionHandler
  • Exception在二进制里是用
Exception table:
         from    to  target type
             0     8    19   Class java/lang/Exception
             0     8    39   any
            19    28    39   any

来表示的。对于finally,是将finally中的代码(可能是因为测试代码很少,编译器做的优化)附加到每一个try/catch可能流程的末尾,然后由finally goto到return行。一个更复杂的分析

  • 构造函数中非final变量的初始化可能被重排到构造函数结束后!!!
  • synchronized块只保证A线程块内部的执行是在B线程进入块之前完成的,并不保证A线程块前的代码会被执行!!!
  • 有几种方法能够做到等待所有子任务完成后继续:
    • ExecutorService.awaitTermination,没什么坑
    • CountDownLatch,专门做这个的多线程工具类,适用性广,非常赞
    • Thread.join + for,这个有一个小点。for循环调用join的时候是顺序的,也就是说,join是按序等待结束的
    • 类初始化是线程安全的,所以多线程可能会互锁,静态块会在这里执行,要小心
    • BlockingQueue的take会block,但遍历不会,会用ReentrantLock来做锁(ArrayBlockingQueue)
    • 混淆对代码的改动匪夷所思,一定要看一下
  • Java对于重载参数的解析发生在编译时,所以,多态的重载并不支持。WTF!!!
  • javac默认报错100个。。。神奇的设置。。。gradle里这样修改
afterEvaluate {
    tasks.withType(JavaCompile) {
        options.compilerArgs << "-Xmaxerrs" << "100000"
    }
}

黑科技

  • DCL式的Singleton在jdk1.5以前是有bug的,因为JMM规定的一致性协议是单线程的as if serial。除非使用volatile强制内存写通
  • Proxy也很慢,平均下来比直接new对象要慢30倍左右(高通615 Android 4.4)
  • 可以通过更改jni层class和method struct中的指针指向替换类和方法,大阿里的一个实现
  • Proxy只能搞interface的实现,想用这个做类功能的替换是不行的
  • LambdaMetafactory可以生成高速的反射调用,java8支持
  • Annotation Processor生成java代码,一定要记得把writer#close掉,要不然后续的javac会忽略生成的类(惨痛教训,查了一个小时,太傻逼了)
  • APT中,文件一旦创建(createResource)并openWriter,不论后续轮次的生成中是否close writer或者删除文件,再open都是会跪掉的,getResource出来的不能openWriter。所以,只要想支持多轮次的生成resource文件,必须使用Writer的成员变量,在finalize中释放(虽然很二)。
  • 对于 @Repeatable 的 annotation,在 APT 的 roundEnv.getElementsAnnotatedWith时,必须同时处理 @Foo 和 @Foos。对于重复的 @Foo,会被默默的转成 @Foos
<think> 嗯,用户这次问的是搭建大数据分析平台环境时的和注意事项。结合之前的对话历史,用户似乎对技术实施细节很感兴趣,之前讨论过apt命令的区别,现在转向更复杂的大数据平台搭建,可能是运维或数据工程师。 用户引用的几段材料里提到几个关键点:数据质量、指标规划、服务器选型和Anaconda安装经验。需要把这些零散信息整合成实用的避指南。特别是引用4里提到的Anaconda安装问题和解决途径,对用户应该很有价值。 从技术角度看,搭建大数据平台的痛点通常集中在环境配置、组件兼容性和资源规划三方面。用户没有说明具体使用场景,但提到“大数据分析平台”,推测可能涉及Hadoop/Spark生态圈。需要覆盖从基础设施到上层工具的完整链条。 注意到用户上次对系统命令的解释很满意,这次也要保持结构化表达。但大数据平台比Linux命令复杂得多,得把注意事项分层说明:硬件层考虑服务器选型(呼应引用3),软件层解决依赖冲突(引用4的经验),数据层强调质量监控(引用1和2)。 特别要提醒用户几个经典陷阱:比如Hadoop集群主机名解析错误、Spark版本与Scala不匹配、磁盘空间不足导致HBase崩溃。这些在实际运维中都是高频问题,引用材料里没提但必须补充。 用户可能最关心如何快速搭建可用环境,所以最后给出分阶段验证建议很关键——从单机伪分布式到完全集群的渐进式部署能降低复杂度。对了,还要强调备份和文档,这是新手最容易忽视的。 </think>搭建大数据分析平台环境时可能遇到的常见问题及注意事项如下,结合实践经验整理成避指南: --- ### **一、典型环境搭建问题(“”)** 1. **依赖冲突** - **问题**:Python库(如NumPy/Pandas)与Hadoop/Spark版本不兼容,或Java版本冲突(如JDK 8与JDK 11切换导致HDFS异常)[^4] - **案例**:`PySpark`调用时因`py4j`版本不匹配报`NoSuchMethodError` - **解决**:使用虚拟环境隔离(如`conda create -n bigdata python=3.8`)并固定依赖版本 2. **集群通信故障** - **现象**:Hadoop集群节点间SSH免密登录失效,或防火墙阻塞端口(如HDFS的50070/8020端口) - **验证**:`telnet <master-ip> 8020`测试连通性 - **处理**:配置`/etc/hosts`主机名解析,关闭防火墙或开放端口 3. **资源分配不足** - **表现**:YARN任务频繁被杀,Spark作业因`OutOfMemoryError`崩溃 - **调优**: - 调整`yarn-site.xml`:`yarn.nodemanager.resource.memory-mb`(单节点可用内存) - 设置Spark:`spark.executor.memory`和`spark.driver.memory`[^3] 4. **存储配置错误** - **HDFS问题**:DataNode未启动(`dfs.datanode.data.dir`权限错误) - **修复**:格式化NameNode前备份数据,执行: ```bash hdfs namenode -format # 谨慎操作!仅初始化时使用 chown -R hdfs:hdfs /data/hdfs # 确保目录属主正确 ``` --- ### **二、关键注意事项** 1. **环境隔离** - 使用`Anaconda`创建独立Python环境(避免污染系统库)[^4] - 配置`JAVA_HOME`统一指向特定JDK版本(如`export JAVA_HOME=/usr/lib/jvm/java-8-openjdk`) 2. **组件版本规划** | 组件 | 推荐版本 | 兼容要点 | |------------|----------------|---------------------------| | Hadoop | 3.3.x | 需JDK 8+ | | Spark | 3.3.x | Scala 2.12兼容 | | Python | 3.8 | PySpark需匹配Scala版本 | 3. **分阶段验证** ```mermaid graph LR A[单机伪分布式] --> B[核心功能测试] B --> C[添加工作节点] C --> D[压力测试] D --> E[生产部署] ``` 4. **监控与日志** - 部署`Prometheus`+`Grafana`监控集群指标(CPU/内存/磁盘IO) - 集中日志:`ELK`(Elasticsearch+Logstash+Kibana)收集`/var/log/hadoop`日志 5. **数据质量保障** - 在数据接入层添加校验规则(如非空检查、值域验证)[^1] - 实施数据血缘追踪(Apache Atlas或自定义工具) --- ### **三、调试技巧** 1. **优先检查日志** - Hadoop:`tail -f /var/log/hadoop/hdfs-namenode.log` - Spark:`spark-submit --verbose`查看详细提交日志 2. **最小化复现**: 从单机模式(`local[*]`)开始测试,再扩展至集群模式 3. **社区资源利用**: - 检索错误关键词 + 组件版本(如“Spark 3.3 NoSuchMethodError KryoSerializer”) - 参考官方文档的`Troubleshooting`章节 > **经验总结**:搭建过程需严格遵循**环境隔离→版本对齐→分步验证→监控兜底**流程。首次部署建议使用Cloudera CDH或Hortonworks HDP等集成发行版减少复杂度[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值