kafka系列五、kafka常用java API
引入maven包
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.1</version>
</dependency>
一、同步发送消息
1、创建topic:
./bin/kafka-topics.sh --create --zookeeper 127.0.0.1:2181 --partitions 3 --replication-factor 1 --topic test-syn
2、代码
package com.example.demo.test; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; public class SynProducer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("acks", "all"); // 发送所有ISR
props.put("retries", 2); // 重试次数
props.put("batch.size", 16384); // 批量发送大小
props.put("buffer.memory", 33554432); // 缓存大小,根据本机内存大小配置
props.put("linger.ms", 1000); // 发送频率,满足任务一个条件发送
props.put("client.id", "producer-syn-1"); // 发送端id,便于统计
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
return props;
} public static void main(String[] args) {
KafkaProducer<String, String> producer = new KafkaProducer<>(getProps());
for(int i=0; i< 1000; i++){
// 三个参数,topic,key:用户分配partition,value:发送的值
ProducerRecord<String, String> record = new ProducerRecord<>("test-syn", "topic_"+i,"test-syn-"+i);
Future<RecordMetadata> metadataFuture = producer.send(record);
RecordMetadata recordMetadata = null;
try {
recordMetadata = metadataFuture.get();
System.out.println("发送成功!");
System.out.println("topic:"+recordMetadata.topic());
System.out.println("partition:"+recordMetadata.partition());
System.out.println("offset:"+recordMetadata.offset());
} catch (InterruptedException|ExecutionException e) {
System.out.println("发送失败!");
e.printStackTrace();
}
} producer.flush();
producer.close();
}
}
3、测试
1、创建consumer
./bin/kafka-console-consumer.sh --bootstrap-server 47.52.199.52: --topic test-syn --group test- --from-beginning
2、运行程序
二、异步发送消息
package com.example.demo.test; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord; import java.util.Properties; public class ASynProducer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("acks", "all"); // 发送所有ISR
props.put("retries", 2); // 重试次数
props.put("batch.size", 16384); // 批量发送大小
props.put("buffer.memory", 33554432); // 缓存大小,根据本机内存大小配置
props.put("linger.ms", 1000); // 发送频率,满足任务一个条件发送
props.put("client.id", "producer-asyn-1"); // 发送端id,便于统计
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
return props;
} public static void main(String[] args) {
KafkaProducer<String, String> producer = new KafkaProducer<>(getProps());
for(int i=0; i< 1000; i++){
ProducerRecord<String, String> record = new ProducerRecord<>("test-asyn", "topic_"+i,"test-asyn-"+i);
// 相比同步发送,异步发送需要传入callback,发送结果回来回调callback方法
producer.send(record, (recordMetadata, e) -> {
if(e != null){
System.out.println("发送失败!");
e.printStackTrace();
}else {
System.out.println("发送成功!");
System.out.println("topic:"+recordMetadata.topic());
System.out.println("partition:"+recordMetadata.partition());
System.out.println("offset:"+recordMetadata.offset());
}
});
} producer.flush();
producer.close();
}
}
三、及时发送消息
相比前两种方式,该方式不关心结果,只管发送,所以比较快。
package com.example.demo.test; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord; import java.util.Properties; public class FireProducer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("acks", "all"); // 发送所有ISR
props.put("retries", 2); // 重试次数
props.put("batch.size", 16384); // 批量发送大小
props.put("buffer.memory", 33554432); // 缓存大小,根据本机内存大小配置
props.put("linger.ms", 1000); // 发送频率,满足任务一个条件发送
props.put("client.id", "producer-syn-1"); // 发送端id,便于统计
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
return props;
} public static void main(String[] args) {
KafkaProducer<String, String> producer = new KafkaProducer<>(getProps());
for(int i=0; i< 1000; i++){
ProducerRecord<String, String> record = new ProducerRecord<>("test-syn", "topic_"+i,"test-syn-"+i);
// 不关心发送结果
producer.send(record);
} producer.flush();
producer.close();
}
}
四、自动提交offset
package com.example.demo.consumer; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.ArrayList;
import java.util.List;
import java.util.Properties; /**
* @author 王柱星
* @version 1.0
* @title
* @time 2018年12月11日
* @since 1.0
*/
public class AutoCommitConsumer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.52:9092");
props.put("group.id", "test_3");
props.put("session.timeout.ms", 30000); // 如果其超时,将会可能触发rebalance并认为已经死去,重新选举Leader
props.put("enable.auto.commit", "true"); // 开启自动提交
props.put("auto.commit.interval.ms", "1000"); // 自动提交时间
props.put("auto.offset.reset","earliest"); // 从最早的offset开始拉取,latest:从最近的offset开始消费
props.put("client.id", "producer-syn-1"); // 发送端id,便于统计
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return props;
} public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
// 拉取任务超时时间
for(;;){
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
} }
} }
五、同步提交
同步提交,提交后broke会阻塞等结果返回,在成功提交或碰到无怯恢复的错误之前,commitSync()会一直重试
package com.example.demo.consumer; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.ArrayList;
import java.util.List;
import java.util.Properties; /**
* @author 王柱星
* @version 1.0
* @title
* @time 2018年12月11日
* @since 1.0
*/
public class CommitConsumer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("group.id", "test_3");
props.put("session.timeout.ms", 30000); // 如果其超时,将会可能触发rebalance并认为已经死去,重新选举Leader
props.put("enable.auto.commit", "false"); // 开启自动提交
props.put("auto.commit.interval.ms", "1000"); // 自动提交时间
props.put("auto.offset.reset","earliest"); // 从最早的offset开始拉取,latest:从最近的offset开始消费
props.put("client.id", "consumer-2"); // 发送端id,便于统计
props.put("max.poll.records","1000"); // 每次批量拉取条数
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return props;
} public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
// 当前批次offset
consumer.commitSync();
} }
} }
六、异步提交
commitAsync()方法提交最后一个偏移量。在成功提交或碰到无怯恢复的错误之前,commitSync()会一直重试,但是commitAsync()不会,这也是commitAsync()不好的一个地方。它之所以不进行重试,是因为在它收到服务器响应的时候, 可能有一个更大的偏移量已经提交成功。假设我们发出一个请求用于提交偏移量2000,这个时候发生了短暂的通信问题,服务器收不到请求,自然也不会作出任何响应。与此同时,我们处理了另外一批消息,并成功提交了偏移量3000。如果commitAsync()重新尝试提交偏移量2000 ,它有可能在偏移量3000之后提交成功。系统会记录最后提交的偏移量,这个时候如果发生再均衡,就会出现重复消息,会从2000开始。
public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
// 当前批次offset
consumer.commitAsync();
}
}
}
异步提交支持回调方法,可以记录提交错误的值
public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
// 当前批次offset
consumer.commitAsync((map, e) -> {
if(e != null){
System.out.println("提交失败:"+map.get(""));
}
});
}
}
}
七、同步和异步组合提交
package com.example.demo.consumer; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import java.util.ArrayList;
import java.util.List;
import java.util.Properties; /**
* @author 王柱星
* @version 1.0
* @title
* @time 2018年12月11日
* @since 1.0
*/
public class CommitAsynCallbackConsumer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("group.id", "test_4");
props.put("session.timeout.ms", 30000); // 如果其超时,将会可能触发rebalance并认为已经死去,重新选举Leader
props.put("enable.auto.commit", "false"); // 开启自动提交
props.put("auto.commit.interval.ms", "1000"); // 自动提交时间
props.put("auto.offset.reset","earliest"); // 从最早的offset开始拉取,latest:从最近的offset开始消费
props.put("client.id", "consumer-3"); // 发送端id,便于统计
props.put("max.poll.records","200"); // 每次批量拉取条数
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return props;
} public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
// 当前批次offset
consumer.commitAsync((map, e) -> {
if(e != null){
System.out.println("提交失败:"+map.get(""));
}
});
}
}
}
}
八、提交到特定的partition、偏移量
public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
} Map<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>();
// 指定topic 、partition
TopicPartition topicPartition = new TopicPartition("producer-syn",0);
// 指定offset
OffsetAndMetadata offsetAndMetadata = new OffsetAndMetadata(100);
// 可以提交多个topic
offsets.put(topicPartition, offsetAndMetadata);
// 提交offset
consumer.commitSync(offsets);
}
}
}
为提高消费吞吐量,可使用线程处理,消费者只负责接收消息,由线程池处理。
九、从特定偏移量处开始消费
前面都是consumer.poll()之后读取该批次的消息,kafka还提供了从分区的开始或者末尾读消息的功能:
seekToEnd(Collection<TopicPartition> partitions)
seekToBeginning(Collection<TopicPartition> partitions)
另外kafka还提供了从指定偏移量处读取消息,可以通过seek()方法来处理:
// 只有先pull一次,seek才会生效,启动后第一次拉取不返回数据
seek(TopicPartition partition, long offset)
示例:
public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
TopicPartition topicPartition = new TopicPartition("producer-syn",0);
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
// 只有先pull一次,seek才会生效,启动后第一次拉取不返回数据
consumer.seek(topicPartition,100L);
// new ArrayList<>(topicPartition)
List list = new ArrayList<>();
list.add(topicPartition);
// consumer.seekToEnd(list);
// consumer.seekToBeginning(list);
consumer.commitSync();
}
}
}
十、从特定时间开始消费
offsetsForTimes(java.util.Map<TopicPartition,java.lang.Long>)
- 入参:parttition、时间戳
- 返回:响应的offset
- 调用 seek(TopicPartition partition, long offset)开始消费
示例:
public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
TopicPartition topicPartition = new TopicPartition("producer-syn",0);
List<String> topics = new ArrayList<>();
topics.add("producer-syn");
consumer.subscribe(topics);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
Map<TopicPartition, Long> timestampsToSearch = new HashMap<>();
// 通过时间戳获取offset
timestampsToSearch.put(topicPartition,1544594780946L);
Map<TopicPartition, OffsetAndTimestamp> timestampMap = consumer.offsetsForTimes(timestampsToSearch);
// 指定offset
consumer.seek(topicPartition,timestampMap.get(topicPartition).offset());
consumer.commitSync();
}
}
}
其他场景:
通过时间戳查询指定分区的offsets,前后两个时间戳就是指定的时间段,所有分区相加就是指定的主题。所以可以通过时间戳查询指定分区的offsets方法来查询指定时间段内指定主题的偏移量。结果可以用来核对生产或者同步的消息数量。
十一、监听rebalance提交
前面我们说过当发生consumer退出或者新增,partition新增的时候会触发再均衡。那么发生再均衡的时候如果某个consumer正在消费的任务没有消费完该如何提交当前消费到的offset呢?kafka提供了再均衡监听器,在发生再均衡之前监听到,当前consumer可以在失去分区所有权之前处理offset关闭句柄等。
消费者API中有一个()方法:
subscribe(Collection<TopicPartition> var1, ConsumerRebalanceListener var2);
ConsumerRebalanceListener对象就是监听器的接口对象,我们需要实现自己的监听器继承该接口。接口里面有两个方法需要实现:
void onPartitionsRevoked(Collection<TopicPartition> var1); void onPartitionsAssigned(Collection<TopicPartition> var1);
第一个方法会在再均衡开始之前和消费者停止读取消息之后被调用。如果在这里提交偏移量,下一个接管分区的消费者就知道该从哪里开始读取了。
第二个会在重新分配分区之后和消费者开始读取消息之前被调用。
示例:
public static void main(String[] args) {
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps()) ;
List<String> topics = new ArrayList<>();
topics.add("test-syn"); // 指定offset
Map<TopicPartition, OffsetAndMetadata> currentOffset = new HashMap<>(); consumer.subscribe(topics, new ConsumerRebalanceListener() {
@Override
public void onPartitionsRevoked(Collection<TopicPartition> collection) {
System.out.println("发生rebalance!提交:"+currentOffset);
consumer.commitAsync(currentOffset,null);
}
@Override
public void onPartitionsAssigned(Collection<TopicPartition> collection) {
}
}); for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
Long offset = 0L;
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
offset = consumerRecord.offset();
} TopicPartition topicPartition = new TopicPartition("test-syn",0);
OffsetAndMetadata offsetAndMetadata = new OffsetAndMetadata(offset);
currentOffset.put(topicPartition, offsetAndMetadata);
consumer.commitSync();
}
}
十二、主动分配分区消费
到目前为止我们讨论的都是消费者群组,分区被自动分配给群组的消费者,群组的消费者有变动会触发再均衡。那么是不是可以回归到别的消息队列的方式:不需要群组消费者也可以自己订阅主题?
kafka也提供了这样的案例,因为kafka的主题有分区的概念,那么如果没有群组就意味着你的自己订阅到特定的一个分区才能消费内容。如果是这样的话,就不需要订阅主题,而是为自己分配分区。一个消费者可以订阅主题(并加入消费者群组),或者为自己分配分区,但不能同时做这两件事情。注:group.id配置不能与其他consumer重复,否则会报错,直接去掉也行。
package com.example.demo.consumer; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties; /**
* @author 王柱星
* @version 1.0
* @title
* @time 2018年12月11日
* @since 1.0
*/
public class PartitionConsumer {
private static Properties getProps(){
Properties props = new Properties();
props.put("bootstrap.servers", "47.52.199.51:9092");
props.put("session.timeout.ms", 30000); // 如果其超时,将会可能触发rebalance并认为已经死去,重新选举Leader
props.put("enable.auto.commit", "false"); // 开启自动提交
props.put("auto.commit.interval.ms", "1000"); // 自动提交时间
props.put("auto.offset.reset","earliest"); // 从最早的offset开始拉取,latest:从最近的offset开始消费
props.put("client.id", "consumer-3"); // 发送端id,便于统计
props.put("max.poll.records","200"); // 每次批量拉取条数
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
return props;
} public static void main(String[] args) {
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getProps())) {
List<PartitionInfo> partitionInfoList = consumer.partitionsFor("test-syn");
List<TopicPartition> topicPartitionList = new ArrayList<>();
if(partitionInfoList != null){
for(PartitionInfo partitionInfo : partitionInfoList){
topicPartitionList.add(new TopicPartition(partitionInfo.topic(),partitionInfo.partition()));
consumer.assign(topicPartitionList);
}
}
Map map = consumer.metrics();
System.out.println(map);
for(;;){
// 拉取任务超时时间
ConsumerRecords<String,String> records = consumer.poll(1000);
for(ConsumerRecord consumerRecord : records){
System.out.println("partition:"+consumerRecord.partition());
System.out.println("offset:"+consumerRecord.offset());
System.out.println("key:"+consumerRecord.key());
System.out.println("value:"+consumerRecord.value());
}
consumer.commitSync();
}
}
} }
注:
- consumer.partitionsFor(“主题”)方法允许我们获取某个主题的分区信息。
- 知道想消费的分区后使用assign()手动为该消费者分配分区。
kafka系列五、kafka常用java API的更多相关文章
- Apache Kafka系列(五) Kafka Connect及FileConnector示例
Apache Kafka系列(一) 起步 Apache Kafka系列(二) 命令行工具(CLI) Apache Kafka系列(三) Java API使用 Apache Kafka系列(四) 多线程 ...
- 算法竞赛中的常用JAVA API :大数类(转载)
5.算法竞赛中的常用JAVA API :大数类 摘要 java中的基础数据类型能存储的最大的二进制数是 2 ^ 63 - 1 对应的十进制数是9223372036854775807(long类型的最大 ...
- Hadoop 系列(三)Java API
Hadoop 系列(三)Java API <dependency> <groupId>org.apache.hadoop</groupId> <artifac ...
- 常用Java API之Ramdom--用代码模拟猜数小游戏
常用Java API之Ramdom Ramdom类用来生成随机数字.使用起来也是三个步骤: 1.导包 import java.util.Random; 2.创建 Random r = new Rand ...
- 常用Java API之Scanner:功能与使用方法
Scanner 常用Java API之Scanner:功能与使用方法 Scanner类的功能:可以实现键盘输入数据到程序当中. 引用类型的一般使用步骤:(Scanner是引用类型的) 1.导包 imp ...
- 算法竞赛中的常用JAVA API:PriorityQueue(优先队列)(转载)
算法竞赛中的常用JAVA API:PriorityQueue(优先队列) PriorityQueue 翻译过来就是优先队列,本质是一个堆, 默认情况下堆顶每次都保留最小值,每插入一个元素,仍动态维护堆 ...
- 算法竞赛中的常用JAVA API :HashSet 和 TreeSet(转载)
算法竞赛中的常用JAVA API :HashSet 和 TreeSet set set容器的特点是不包含重复元素,也就是说自动去重. HashSet HashSet基于哈希表实现,无序. add(E ...
- 算法竞赛中的常用JAVA API :HashMap 和 TreeMap(转载)
算法竞赛中的常用JAVA API :HashMap 和 TreeMap 摘要 本文主要介绍Map接口下的HashMap和TreeMap. HashMap HashMap是基于哈希表的 Map 接口的实 ...
- 8.算法竞赛中的常用JAVA API :Calendar日期类
8.算法竞赛中的常用JAVA API :Calendar日期类 摘要 在蓝桥杯中有关于日期计算的问题,正好java中的Date类和Calendar类提供了对日期处理的一些方法.Date类大部分方法已经 ...
- 7.算法竞赛中的常用JAVA API :String 、StringBuilder、StringBuffer常用方法和区别(转载)
7.算法竞赛中的常用JAVA API :String .StringBuilder.StringBuffer常用方法和区别 摘要 本文将介绍String.StringBuilder类的常用方法. 在j ...
随机推荐
- cf860E Arkady and A Nobody-men (树剖)
容易得出,如果我们按照深度一层一层地做,做完一层后,这层某个点的答案就是它的祖先们的子树大小(统计大小时不包括树根) 由于我太菜了不会别的方法,虽然N是5e5的,还是只好用一个树剖(树状数组降常数)水 ...
- vlc sdl 播放视频可随窗口改变大小
#include <stdio.h> #include <stdint.h> #include <math.h> #include <stdlib.h> ...
- Segment 李超线段树
题目大意: 要求在平面直角坐标系下维护两个操作: 1.在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 2.给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号. 若 ...
- 【LOJ#6278】数列分块2
题目大意:分块维护一个有 n 个数字的序列,有两种操作:区间加,区间查询小于某个数的元素个数.n <= 50000 预处理阶段:处理出块内元素的相对大小顺序(排序),时间复杂度为 \(O(nlo ...
- [hdu6148][Valley Numer]
hdu6148 思路 一个数位dp模板题,注意判断前导0.用一个bz来记录当前是应该增还是可增可减.然后排除不满足条件的情况并进行dp即可. 代码 #include<cstdio> #in ...
- (转)Maven仓库——私服介绍
背景:对Maven私服一直想做个深入的总结,因为不了解,所以感觉很陌生. 转载地址:http://blog.csdn.net/catoop/article/details/62312477 常用功能和 ...
- 搞定 Kubernetes 基于flannel 的集群网络
.Docker网络模式 在讨论Kubernetes网络之前,让我们先来看一下Docker网络.Docker采用插件化的网络模式,默认提供bridge.host.none.overlay.maclan和 ...
- python自定义函数的参数之四种表现形式
(1)def a(x,y):print x,y 这是最常见的定义方式,调用该函数,a(1,2)则x取1,y取2,形参与实参相对应,如果a(1)或者a(1,2,3)则会报错 (2)def a(x,y=3 ...
- npm脚本
在package.json的script里面我们可以写很多npm脚本,下面我来总结一下一些日常遇到的知识点: 1.npm_lifecycle_event npm 提供一个npm_lifecycle_e ...
- Bandicam录制视频
我已经录制了一个视频,关于怎么录制视频的,原画画质的嘻嘻.视频地址 http://www.tudou.com/programs/view/T7xzG1CgsD4 ------------------ ...