C++异常处理机制(超级详细)

2023-11-12

目录

0.异常处理机制简介

1.传统错误处理机制(通过函数返回值)

2.异常处理机制语法 

​3.异常接口声明

4.异常类型和声明周期

4.1throw基本类型异常(int 、float、char.....)

4.2throw字符串类型异常

​ 4.3throw类对象类型异常

4.3.1第一种:抛出匿名对象,使用形参接收

​4.3.2第二种: 抛出局部变量,使用形参接收

4.3.3第三种:抛出匿名对象,使用引用接收(代码优化 )

5.异常和继承

6. 额外补充——标准库里的异常类


0.异常处理机制简介

异常无处不在,程序随时可能误入歧途!C++ 提出了新的异常处理机制!

异常是一种程序控制机制,与函数机制互补。

函数是一种以栈结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它可以在出现“意外”时中断当前函数,并以某种机制(类型匹配)回馈给隔代的调用者相关的信息。

 图像示例:

当C函数发生错误时,不需要将错误一级级 返回给main,利用异常,直接返回给main:

1.传统错误处理机制(通过函数返回值)

需求: 实现文件的二进制拷贝(当希望文件能够原封不动的拷贝时,要用二进制拷贝)

将要拷贝文件:

代码实现:

// demo 15-14  
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 1024

//实现文件的二进制拷贝
int copyfile(const char* dest, const char* src) {
	FILE* fp1 = NULL, * fp2 = NULL;

	//rb 只读方式打开一个二进制文件,只允许读取数据
	fopen_s(&fp1, src, "rb");

	if (fp1 == NULL) {
		return -1;
	}

	//wb 以只写的方式打开或新建一个二进制文件,只允许写数据。
	fopen_s(&fp2, dest, "wb");
	if (fp2 == NULL) {
		return -2;
	}

	char buffer[BUFSIZE];
	int readlen, writelen;

	//如果读到数据,则大于0
	while ((readlen = fread(buffer, 1, BUFSIZE, fp1)) > 0) {
		writelen = fwrite(buffer, 1, readlen, fp2);
		if (readlen != writelen) {
			return -3;
		}
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

void main() {
	int ret = 0;
    //temp.txt为要拷贝的文件,CopyTemp.txt为拷贝文件
	ret = copyfile("CopyTemp.txt","temp.txt");

	if (ret != 0) {
		switch (ret) {
		case -1:
			printf("打开源文件失败!\n");
			break;
		case -2:
			printf("打开目标文件失败!\n");
			break;
		case -3:
			printf("拷贝文件时失败!\n");
			break;
		default:
			printf("出现未知的情况!\n");
			break;
		}
	}
	system("pause");
}

运行截图:

拷贝文档截图:  

当temp.txt文档不存在时,运行截图:

传统错误返回需要一层层返回错误,而异常处理可以直接到达能够处理异常的地方。

2.异常处理机制语法 

异常发生第一现场,抛出异常
void  function( ){
        //... ...
          throw 表达式;
        //... ...
}
在需要关注异常的地方,捕捉异常
try{
        //程序
        function();        把function至于try中
        //程序
}catch(异常类型声明){        比如只写一个int
        //... 异常处理代码 ...
}catch(异常类型 形参){       形参将会取得抛出的值
        //... 异常处理代码 ...
}catch(...){               抛出的其它异常类型,可以接收任意类型
        //
}
如果没有catch(...),并且没有catch子句与抛出的异常类型匹配,程序会直接中断报错。

修改“文件的二进制拷贝”代码:

// demo 15-16  
#include <stdio.h>
#include <stdlib.h>
#include <string>

using namespace std;

#define BUFSIZE 1024

//实现文件的二进制拷贝
int copyfile2(const char* dest, const char* src) {
	FILE* fp1 = NULL, * fp2 = NULL;

	//通过throw操作创建一个异常对象并抛掷
	//rb 只读方式打开一个二进制文件,只允许读取数据
	fopen_s(&fp1, src, "rb");

	if (fp1 == NULL) {
		throw new string("文件不存在");
	}

	//wb 以只写的方式打开或新建一个二进制文件,只允许写数据。
	fopen_s(&fp2, dest, "wb");
	if (fp2 == NULL) {
		throw  0.01f;;
	}

	char buffer[BUFSIZE];
	int readlen, writelen;

	//如果读到数据,则大于0
	while ((readlen = fread(buffer, 1, BUFSIZE, fp1)) > 0) {
		writelen = fwrite(buffer, 1, readlen, fp2);
		if (readlen != writelen) {
			throw - 3;
		}
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

//这种写法是将copyfile2的抛出异常给copyfile1,copyfile1再给main 
int copyfile1(const char* dest, const char* src) {
	try {
		copyfile2(dest, src);
	}
	catch (float e) {
		//throw ;
		printf("copyfile1 - catch ...\n");

		//提示:处理不了的异常,我们可以在catch的最后一个分支,使用throw语法,继续向调用者throw。就比如再抛给main~
		throw;  //throw后面可以写接收到的e,也可以不写,不写的话会给出“未使用局部变量”的警告
	}

	return 0;
}

void main() {
	int ret = 0;

	//在需要捕捉异常的地方,将可能抛出异常的程序段嵌在try块之中
	//按正常的程序顺序执行到达try语句,然后执行try块{}内的保护段
	//如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行,程序从try块后跟随
    //的最后一个catch子句后面的语句继续执行下去
	try {//保护段
		printf("开始执行 copyfile1...\n");
		ret = copyfile1("CopyTemp.txt", "temp.txt");
		printf("执行 copyfile1 完毕\n");

		//catch子句按其在try块后出现的顺序被检查,匹配的catch子句将捕获并按catch子句中的代码
        //处理异常(或继续抛掷异常)
	}
	catch (int error) {
		printf("出现异常啦!%d\n", error);
	}
	catch (string* error) {
		printf("捕捉到字符串异常:%s\n", error->c_str());
		delete error;
	}
	catch (float error) {
		printf("出现异常啦!%f\n", error);
	}
	catch (...) {
		printf("catch ...\n");
	}


	//如果没有找到匹配,则缺省功能是调用abort终止程序。

	system("pause");
}

 注意:

1.throw后面可跟任何表达式,除了整数外,指针、字符常量等也可以,如:throw "文档打开失败"

2.通过throw操作创建一个异常对象并抛掷

3.在需要捕捉异常的地方,将可能抛出异常的程序段嵌在try块之中

4.按正常的程序顺序执行到达try语句,然后执行try块{}内的保护段

5.如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行,程序从try块后跟随的最后一个catch子句后面的语句继续执行下去

6.catch子句按其在try块后出现的顺序被检查,匹配的catch子句将捕获并按catch子句中的代码处理异常(或继续抛掷异常)

7.如果没有找到匹配,则缺省功能是调用abort终止程序。

运行结果:

当temp.txt文档不存在,运行结果:

3.异常接口声明

可以在函数声明中列出可能抛出的所有异常类型,加强程序的可读性。

如:

int copyfile2(char *dest, char *src) throw (float, string *, int)  { }

这样,在阅读代码时便可知这个函数会抛出float、string*和int类型异常,增加可读性

注意:

1.对于异常接口的声明,函数声明中列出可能抛出的所有异常类型

2.如果没有包含异常接口声明,此函数可以抛出任何类型的异常

3.如果函数声明中有列出可能抛出的所有异常类型,那么抛出其它类型的异常讲可能导致程序终止(对于有些编译器可以抛出其它未在声明列表中的异常类型,如老式VC++)

4.如果一个函数不想抛出任何异常,可以使用 throw () 声明(有些编译器会警告throw(),如老式VC++)

4.异常类型和声明周期

4.1throw基本类型异常(int 、float、char.....)

// demo 15-17
#include <stdio.h>
#include <stdlib.h>
#include <string>

using namespace std;

#define BUFSIZE 1024


//实现文件的二进制拷贝

//第一种情况,throw 普通类型,和函数返回传值是一样的
int copyfile2(const char *dest, const char *src){
	FILE *fp1 = NULL, *fp2 = NULL;

	//rb 只读方式打开一个二进制文件,只允许读取数据
	fopen_s(&fp1, src, "rb");

	if(fp1 == NULL){
		//int ret = -1;
		char ret = 'a';
		throw ret;
	}

	//wb 以只写的方式打开或新建一个二进制文件,只允许写数据。
	fopen_s(&fp2, dest, "wb");
	if(fp2 == NULL){
		throw -2;
	}

	char buffer[BUFSIZE];
	int readlen, writelen;

	//如果读到数据,则大于0
	while( (readlen = fread(buffer, 1, BUFSIZE, fp1)) > 0 ){
		writelen = fwrite(buffer, 1, readlen, fp2);
		if(readlen != writelen){
			throw -3 ;
		}
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

int copyfile1(const char *dest, const char *src){
	return copyfile2(dest, src);
}

void main(){
	int ret = 0;

	
	try{//保护段
		//printf("开始执行 copyfile1...\n");
		ret = copyfile1("CopyTemp.txt", "temp.txt");
		//printf("执行 copyfile1 完毕\n");
			
	}catch(int error){
		printf("出现异常啦!%d\n", error);    //error周期只在此语句中
	}catch(char error){
		printf("出现异常啦!%c\n", error);    //error周期只在此语句中
	}

	system("pause");
}  

对于基本类型异常,使用对应的类型 catch捕捉即可~。

4.2throw字符串类型异常

// demo 15-18
#include <stdio.h>
#include <stdlib.h>
#include <string>

using namespace std;

#define BUFSIZE 1024


int copyfile3(const char* dest, const char* src) {
	FILE* fp1 = NULL, * fp2 = NULL;

	//rb 只读方式打开一个二进制文件,只允许读取数据
	fopen_s(&fp1, src, "rb");

	if (fp1 == NULL) {
		const char* error = "大佬,你的源文件打开有问题";
		printf("throw 前,error 的地址:%p\n", error);
//第二种情况,throw 字符串类型,实际抛出的指针,而且,修饰指针的const 也要严格进行类型匹配
		throw error;  //常量字符串类型,返回的是个地址
	}

	//wb 以只写的方式打开或新建一个二进制文件,只允许写数据。
	fopen_s(&fp2, dest, "wb");
	if (fp2 == NULL) {
		throw - 2;
	}

	char buffer[BUFSIZE];
	int readlen, writelen;

	//如果读到数据,则大于0
	while ((readlen = fread(buffer, 1, BUFSIZE, fp1)) > 0) {
		writelen = fwrite(buffer, 1, readlen, fp2);
		if (readlen != writelen) {
			throw - 3;
		}
	}

	fclose(fp1);
	fclose(fp2);
	return 0;
}

int copyfile1(const char* dest, const char* src) {
	return copyfile3(dest, src);
}

void main() {
	int ret = 0;

	try {//保护段
		//printf("开始执行 copyfile1...\n");
		ret = copyfile1("CopyTemp.txt", "temp.txt");
		//printf("执行 copyfile1 完毕\n");

	}
	catch (int error) {
		printf("出现异常啦!%d\n", error);
	}
	catch (char error) {
		printf("出现异常啦!%c\n", error);
	}
	catch (string error) {
		printf("出现异常啦!%s\n", error.c_str());
	}
//严格类型匹配,这里也需要加const
	catch (const char* error) {   //接收常量字符串类型异常地址
		printf("出现异常啦(char *)!%s(地址:%p)\n", error, error);
	}
	catch (...) {
		printf("没捉到具体的异常类型\n");
	}

	system("pause");
}

当抛出的异常类型为地址(指针)时候,catch捕捉类型也要为指针。并且,当抛出异常类型有const修饰时,捕捉类型也要有cosnt修饰。即严格类型匹配。

运行结果:

4.3throw类对象类型异常

当抛出的异常类型为一个类对象时:

#include <stdio.h>
#include <stdlib.h>
#include <string>



class ErrorException {
public:
	ErrorException() {
		id = 0;
		printf("ErrorException  构造!\n");
	}

	~ErrorException() {
		printf("ErrorException  ~析构!(id: %d)\n", id);
	}

	ErrorException(const ErrorException& e) {
		id = 1;
		printf("ErrorException  拷贝构造函数!\n");
	}

	int  id;
};


下面对throw语句进行分类研究: 

4.3.1第一种:抛出匿名对象,使用形参接收


throw ErrorException(); //抛出匿名对象

catch (ErrorException error) {
		printf("出现异常啦!捕捉到 ErrorException 类型 id: %d\n", error.id);
}

运行结果:

4.3.2第二种: 抛出局部变量,使用形参接收

ErrorException error1;
throw error1; 

catch (ErrorException error) {
        error.id=2;   //增加一句error.id=2,便于惯出
		printf("出现异常啦!捕捉到 ErrorException 类型 id: %d\n", error.id);
}

运行结果:

由以上两种结果可得,不管是抛出匿名对象,还是抛出局部变量,程序都会生成一个匿名对象,并且,当catch是普通参数时,程序还要再次调用拷贝函数。 

4.3.3第三种:抛出匿名对象,使用引用接收(代码优化 )

throw ErrorException();   //直接抛出匿名对象
	
catch (ErrorException& error) {   用引用方式来接
		//error.id = 2;
		printf("出现异常啦!捕捉到 ErrorException &类型 id: %d\n", error.id);
}

 运行结果: 

当然也可以 动态分配内存,直接抛出指针,当然也要用指针接收。(严格类型匹配)

throw new ErrorException();

catch (ErrorException* error) {
		printf("出现异常啦!捕捉到 ErrorException *类型 id: %d\n", error->id);
		delete error;
}

运行结果:

 注意: 引用和普通的形参传值不能共存!

因为引用和普通形参都可以catch捕捉,编译器无法识别被哪个捕捉 。

5.异常和继承

异常也是类,我们可以创建自己的异常类,在异常中可以使用(虚函数,派生,引用传递和数据成员等)。

 案例:设计一个数组类容器 Vector,重载[]操作,数组初始化时,对数组的个数进行有效检查

1.index<0 抛出异常errNegativeException  

2.index = 0 抛出异常 errZeroException

3.index>1000抛出异常errTooBigException 

4.index<10 抛出异常errTooSmallException 

5.errSizeException类是以上类的父类,实现有参数构造、并定义virtual void printError()

Vector容器实现:

#include<iostream>
using namespace std;

class Vector{
public:
	Vector(int length = 128); 
	int getLength();
	int& operator[](int index);
	~Vector();
private:
	int*m_base;
	int m_length;
};

Vector::Vector(int length) {
	m_length = length;
	m_base = new int[length];
}

int Vector::getLength() {
	return m_length;
}

//引用方式返回可以作为左值修改(即存储,Vector va(5);  va[1]=0)
int& Vector::operator[](int index) {
	return m_base[index];
}

Vector::~Vector() {
	if (m_base) {
		delete[] m_base;
		m_length = 0;
	}
}

异常类实现:

class errNegativeException {

};
class errZeroException {

};
class errTooBigException {

};
class errTooSmallException {

};

修改Vector的构造函数:

Vector::Vector(int length) {
	if (length < 0) {
		throw errNegativeException();
	}
	else if (length == 0) {
		throw errZeroException();
	}
	else if (length > 1000) {
		throw errTooBigException();
	}
	else if (length <= 10) {
		throw errTooSmallException();
	}
	m_length = length;
	m_base = new int[length]; 
}

实现主函数接口:

int main() {
	try {
		Vector va(10);
		for (int i = 0; i < va.getLength(); i++) {
			va[i] = i + 3;
		}
	}
	catch (errNegativeException& erro) {
		cout << "errNegativeException" << endl;
	}
	catch (errZeroException& erro) {
		cout << "errZeroException" << endl;
	}
	catch (errTooBigException& erro) {
		cout << "errTooBigException" << endl;
	}
	catch (errTooSmallException& erro) {
		cout << "errTooSmallException" << endl;
	}
	
	system("pause");
	return 0;
}

 运行结果:

 这种抛出异常方法跟直接return一个结果没啥两样,现在通过以前学习的虚函数进行代码优化: 

异常类代码优化:

class errSizeException {
public:
	errSizeException(int size) {
		m_size = size;
	}
	virtual void printErroe() {
		cout << "size:" << m_size << endl;
	}
protected:
	int m_size;
};
//子类errNegativeException 
class errNegativeException :public errSizeException {
public:
	errNegativeException(int size) :errSizeException(size){}
	virtual void printErroe() {
		cout << "errNegativeException size:" << m_size << endl;
	}
};
//子类errZeroException 
class errZeroException :public errSizeException {
public:
	errZeroException(int size) :errSizeException(size) {}
	virtual void printErroe() {
		cout << "errZeroException size:" << m_size << endl;
	}
};
//子类errTooBigException 
class errTooBigException :public errSizeException {
public:
	errTooBigException(int size) :errSizeException(size) {}
	virtual void printErroe() {
		cout << "errTooBigException size:" << m_size << endl;
	}
};
//子类errTooSmallException 
class errTooSmallException :public errSizeException {
public:
	errTooSmallException(int size) :errSizeException(size) {}
	virtual void printErroe() {
		cout << "errTooSmallException size:" << m_size << endl;
	}
};

父类是 errSizeException,子类继承父类。通过虚函数,实现子类代替父类。

主函数接口:


int main() {
	try {
		Vector va(10);
		for (int i = 0; i < va.getLength(); i++) {
			va[i] = i + 3;
		}
	}
	catch (errSizeException& erro) {
		erro.printErroe();
	}

	
	system("pause");
	return 0;
}

运行结果:

6. 额外补充——标准库里的异常类

无需硬背,混个眼熟即可~

代码示例:

#include <iostream>
#include <exception>
#include <stdexcept>

using namespace std;

class Student{
public:
	Student(int age){
		if(age > 249){
			throw out_of_range("年龄太大,你是外星人嘛?");
		}
		m_age = age;
		m_space = new int[1024*1024*100];
	}

private :
	int m_age;
	int *m_space;
};


void main(){

	try{
		for(int i=1; i<1024; i++){
			Student * xiao6lang = new Student(18);
		}
	}catch(out_of_range &e){
		cout<<"捕捉到一只异常:"<<e.what()<<endl;
	}catch(bad_alloc &e){
		cout<<"捕捉到动态内存分配的异常:"<<e.what()<<endl; 
	}

	system("pause");
}

运行结果:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++异常处理机制(超级详细) 的相关文章

  • 将集合绑定到自定义控件属性

    我没有运气尝试将数据集合绑定到我的自定义控件的属性 我已经实现了该控件的字符串属性的机制 在此处提供了一些帮助 并期望集合类型同样简单 但是我无法让它再次工作 这是我的自定义控件视图
  • 尚未注册类型“IServiceProviderFactory[Autofac.ContainerBuilder]”的服务

    当运行以下命令添加数据库迁移脚本时 出现以下错误 dotnet ef migrations add InitialCreate v o Migrations context MyContext 访问 Microsoft Extensions
  • 使用 mono/nunit-console/4 在 Mac OS X 控制台上运行测试

    我安装了 Max OS X 10 11 1 上面装有 Xamarin 我编写了简单的测试类 只是为了测试在 Mac OS X 和 Ubuntu 上运行 Nunit 测试 该类实际上有一个返回字符串的方法 using System names
  • 有没有快速创建集合的方法?

    目前我正在创建一个像这样的新集 std set a s s insert a1 s insert a2 s insert a3 s insert a10 有没有办法创建s在一行 int myints 10 20 30 40 50 std s
  • 在 C# 中按元素相乘数组具有意想不到的性能

    我想找到按元素相乘两个数组的最佳方法 这是更广泛项目的一部分 其中性能而不是唯一的考虑因素 我今天开始用 C Linqpad 编写一些函数 因此它还没有以任何方式进行优化 下面代码的输出如下 Environment ProcessorCou
  • 在 Xamarin 中隐藏软键盘

    如何隐藏软键盘以便在聚焦时显示Entry在 Xamarin forms 便携式表单项目中 我假设我们必须为此编写特定于平台的渲染器 但以下内容不起作用 我创建自己的条目子类 public class MyExtendedEntry Entr
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 如何获取 QTableView 的标题列表?

    我有一个QTableView我的对话框中的对象 我需要访问该表的水平标题并将它们放入QStringList object 尽管进行了大量搜索 但我在 Qt 文档中找不到如何获取此标头列表 编辑 我发现的最接近的地方是this https w
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 为什么 set_symmetry_difference 无法与比较器一起使用?

    Example program include
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • 运行选定的代码生成器时出错:“未将对象引用设置到对象的实例。”错误?

    我已经尝试了所有解决方案 例如修复 VS 2013 但没有用 当您通过右键单击控制器文件夹来创建控制器并添加控制器时 然后右键单击新创建的控制器的操作并选择添加视图 当我尝试创建视图时 就会发生这种情况 它不是一个新项目 而是一个现有项目
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • IEnumerable.Except 不起作用,那么我该怎么办?

    我有一个 linq to sql 数据库 非常简单 我们有 3 个表 项目和用户 有一个名为 User Projects 的连接表将它们连接在一起 我已经有了一个获得的工作方法IEnumberable
  • 新任务中使用的依赖注入服务

    我在需要时使用依赖项注入来访问我的服务 但我现在想要创建一个并发任务 但这会由于依赖项注入对象及其生命周期而导致问题 我读过这篇文章 标题 防止多线程 Link http mehdi me ambient dbcontext in ef6
  • 跨多个域的 ASP.NET 会话

    是否有合适的 NET 解决方案来在多个域上提供持久服务器会话 即 如果该网站的用户在 www site1 com 下登录 他们也将在 www site2 com 下登录 安全是我们正在开发的程序的一个问题 Thanks 它是否需要在会话中
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • 如何在 DropDownList 中保留空格 - ASP.net MVC Razor 视图

    我在视图中通过以下方式绑定我的模型 问题是我的项目文本是格式化文本 单词之间有空格 如下所示 123 First 234 00 123 AnotherItem 234 00 123 Second 234 00 我想保留此项目文本中的空格 即
  • 使我的 COM 程序集调用异步

    我刚刚 赢得 了在当前工作中维护用 C 编码的遗留库的特权 这个dll 公开使用 Uniface 构建的大型遗留系统的方法 除了调用 COM 对象之外别无选择 充当此遗留系统与另一个系统的 API 之间的链接 在某些情况下 使用 WinFo

随机推荐

  • hadoop join之map side join

    在本例中 我们仍然采用上一例中的数据文件 之所以存在reduce side join 是因为在map阶段不能获取所有需要的join字段 即 同一个key对应的字段可能位于不同map中 Reduce side join是非常低效的 因为shu
  • 前端向后台传值的方式及相关注解

    文章目录 传参方式 QueryString传参 访问路径传参 form表单传参 ajax方式进行JSON传参 常用注解 RequestBody RequestParam 为前端提供接口 需要对传参方式有所熟悉 以下有几种常用的传参方式和常见
  • 连接vc显示服务器无法解释客户端请,vc服务器和客户端配置

    vc服务器和客户端配置 内容精选 换一换 当出现以下问题时 可以参考本章节排查解决 可以直接访问后端业务 但是无法通过负载均衡访问后端业务 通过私网IP可以访问负载均衡 但是公网IP无法访问负载均衡 后端服务器健康检查异常 客户端通过负载均
  • NDK与Cygwin配置

    1 Android 开发环境搭建 Android开发环境搭建不是重点 相信看此文章的很多人都已经搭建成功 这里随便概述性的说说 下载 JDK 下载 Eclipse 下载 Android SDK 启动Eclipse 安装 ADT 2 下载安装
  • java中optional 常用用法

    Java中的Optional是一个容器对象 它可以包含一个非空值 也可以为空 它的主要作用是在编写代码时避免空指针异常 java 8 中Optional的完整用法如下 1 创建Optional对象 可以通过of 方法创建一个包含非空值的Op
  • SpringCloud Ribbon(负载均衡)

    1 SpringCloud Ribbon 是一个客户端的负载均衡组件 主要提供负载均衡算法 2 Ribbon中负载均衡算法实现 AbstractLoadBalancerRule 负载均衡策略的抽象类 在该抽象类中定义了负载均衡器ILoadB
  • LDO的dropout voltage

    目录 从一个设计错误谈起 Dropout压降 从芯片内部电路结构理解dropout压降 MOS管 gt 低dropout压降的LDO 进一步降低dropout压降的方法 在系统设计中 电源管理是不可或缺的 而LDO 线性稳压器 是电源管理器
  • Vue生命周期详解

    Vue的生命周期 Vue实例有一个完整的生命周期 也就是从开始创建初女台化数据 编译模板 挂载DOM 渲染一更新一渲染 卸载等一系列过程 我们称这是Vue的生命周期 在Vue官网有这样一张图 生命周期 vue实例从创建到销毁的过程 声明周期
  • android卡刷包自制rom之添加删除,添加/删除ROM内置APP的教程

    ROM闪存软件包是Android闪存中必不可少的东西删除刷机包自带软件 但是大多数ROM闪存软件包都与许多应用程序集成在一起 其中许多不是您想要的 也没有您想要的应用程序 使用Mushroom ROM Assistant快速删除和添加APK
  • 偏最小二乘法(PLS)计算流程

    根据相关文献 将PLS的计算流程整理如下 供大家参考 1 输入样本矩阵X 输出值矩阵Y分别对X Y进行中心化处理 归一化方差 得到矩阵 E0和F 2 令n 0 3 计算矩阵En FF En 计算En FF En的最大特征根对应的单位特征向量
  • AndroidStudio会在@NonNull后面自动添加@org.jetbrains.annotations.Nullable

    今天呀在AndroidStudio 4 1中一直有个问题困扰着我 那就是AndroidStudio会在 NonNull后面自动添加 org jetbrains annotations Nullable 这 自动添加就算了还报错 每次都要删除
  • 区块链搬砖实战

    前言 相信不少币友在数字货币交易的时候都发现了 不同的交易平台不同的数字货币都存在一定的差价 这时候就引出了 搬砖的概念 搬砖的概念 由于各种因素导致各平台的虚拟货币的价格有价格差 产生了套利空间 运用平台之间价格差来谋求利益的行为俗称 搬
  • vs code终端修改字体大小以及其它样式

    1 在文件 gt 首选项 gt 设置 2 用户 gt 工作台 gt 找到settings json点击进入 3 在 settings json文件里添加需要修改的样式 terminal integrated cursorBlinking t
  • 软件资源下载链接

    1 Dreamweaver DW cs5 链接 https pan baidu com s 1kVqqpqJ 密码 9hc4 DW cc2014 链接 https pan baidu com s 1skQvBCL 密码 3kd8 DW cc
  • 数据库系统——复习总结

    数据库系统
  • cvCanny检测边缘,连通重要的非连通区域

    这个函数就是使用canny边缘检测算子检测图象的边缘 在opencv下使用这个函数之前最好将图象平滑处理一下 要不然可能检测不到边缘 检测到的边缘 这些边缘大多还不是连通区域 可以通过3 3的模板将一些相近的边缘连接起来 也可以用cvDil
  • Tesseract-OCR的配置和应用

    1 百度搜索Tesseract OCR下载 Tesseract orc setup 3 02 02 exe 要记得自己的安装目录 博主的安装路径为 C Program Files x86 Tesseract OCR 等会配置环境变量要用 如
  • C# Selenium chromedriver 隐藏Devtool控制台窗口

    爬取网页信息时 使用了C Selenium WebDriver dll chromedriver Chrome 除了chromedriver控制台窗口 可以通过CDS HideCommandPromptWindow true隐藏 还有出现一
  • Health Kit基于数据提供专业方案,改善用户睡眠质量

    什么是CBT I 中国社科院等机构今年发布的 中国睡眠研究报告2023 内容显示 2022年 受访者的每晚平均睡眠时长为7 40小时 近半数受访者的每晚平均睡眠时长不足8小时 47 55 16 79 的受访者的每晚平均睡眠时长不足7小时 这
  • C++异常处理机制(超级详细)

    目录 0 异常处理机制简介 1 传统错误处理机制 通过函数返回值 2 异常处理机制语法 3 异常接口声明 4 异常类型和声明周期 4 1throw基本类型异常 int float char 4 2throw字符串类型异常 4 3throw类