SpringBoot的異常處理流程是什么樣的?
一、默認(rèn)異常處理機(jī)制
默認(rèn)情況下,SpringBoot 提供 /error 請(qǐng)求,來處理所有異常的。
1.瀏覽器客戶端,請(qǐng)求頭里的屬性是Accept:text/html。表明它想要一個(gè)html類型的文本數(shù)據(jù)。因此返回的錯(cuò)誤視圖以HTML格式呈現(xiàn),也就是響應(yīng)一個(gè)“ whitelabel”錯(cuò)誤視圖。

2.如果是其他客戶端,請(qǐng)求頭里的屬性是Accept:/,默認(rèn)響應(yīng)一個(gè)json數(shù)據(jù) 。
二、異常處理流程
介紹異常處理流程前,要先認(rèn)識(shí)HandlerExceptionResolver:處理器異常解析器接口,可以將異常映射到相應(yīng)的統(tǒng)一錯(cuò)誤界面,從而顯示用戶友好的界面(而不是給用戶看到具體的錯(cuò)誤信息)
public interface HandlerExceptionResolver {
//解析處理異常
ModelAndView resolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
在DispatcherServlet初始化時(shí),已經(jīng)把所有的HandlerExceptionResolver處理器異常解析器接口的實(shí)現(xiàn)類放到下面的集合里了
public class DispatcherServlet extends FrameworkServlet {
//異常解析器集合
private List<HandlerExceptionResolver> handlerExceptionResolvers;
}

從上圖可以看出該集合里有DefaultErrorAttributes;還有HandlerExceptionResolverComposite處理器異常解析器組合,這里面包含了三個(gè)能真正處理異常的解析器,分別是ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver。下面會(huì)介紹他們幾個(gè)分別用于處理什么異常。
閱讀doDispatch()方法的源碼可以看出,Spring MVC對(duì)整個(gè)doDispatch()方法用了嵌套的try-catch語句
- 內(nèi)層的try-catch用于捕獲
HandlerMapping進(jìn)行映射查找HandlerExecutionChain以及HandlerAdapter執(zhí)行具體Handler時(shí)的處理異常,并將異常傳入到processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)方法中。外層try-catch用于捕獲渲染視圖時(shí)的異常。 - 通過兩層嵌套的
try-catch,SpringMVC就能夠捕獲到三大組件在處理用戶請(qǐng)求時(shí)的異常,通過這樣的方法能夠很方便的實(shí)現(xiàn)統(tǒng)一的異常處理。
//處理分發(fā)結(jié)果
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
//判斷HandlerMapping、HandlerAdapter處理時(shí)的異常是否為空
if (exception != null) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//異常不為空,處理異常,進(jìn)行異常視圖的獲取
mv = processHandlerException(request, response, handler, exception);
}
//只要存在mv就進(jìn)行視圖渲染
if (mv != null && !mv.wasCleared()) {
//不管視圖是正常視圖還是異常視圖,均進(jìn)入視圖渲染流程
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
...略
...略
...略
}
從上面代碼可以看出,當(dāng)出現(xiàn)異常時(shí)會(huì)進(jìn)入processHandlerException()方法進(jìn)行異常視圖的獲取,處理完成后返回是ModelAndView對(duì)象。接下來不管視圖是正常視圖還是異常視圖,只要ModelAndView不為空,均進(jìn)入視圖渲染流程。下面是如何進(jìn)行進(jìn)行異常視圖的獲取的代碼。
//處理異常,進(jìn)行異常視圖的獲取
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
//遍歷所有的處理器異常解析器handlerExceptionResolvers,看誰能夠處理當(dāng)前異常
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
//解析當(dāng)前異常
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
//ModelAndView 不為空時(shí),異常視圖獲取成功,跳出方法,進(jìn)行異常視圖渲染。
break;
}
}
...略
...略
...略
//所有處理器異常解析器都不能處理該異常,拋出異常
throw ex;
}
遍歷所有的處理器異常解析器handlerExceptionResolvers,看誰能夠處理當(dāng)前異常
DefaultErrorAttributes先來處理異常。把異常信息保存到request域,并且返回null,并不能真正解析。HandlerExceptionResolverComposite會(huì)遍歷它包含的三個(gè)異常解析器處理異常ExceptionHandlerExceptionResolver處理器異常解析器支持@ControllerAdvice+@ExceptionHandler處理全局異常ResponseStatusExceptionResolver處理器異常解析器支持@ResponseStatus+自定義異常DefaultHandlerExceptionResolver處理器異常解析器支持Spring底層的異常
當(dāng)沒有任何異常解析器能夠處理異常,異常就會(huì)被拋出,最終Tomcat會(huì)發(fā)送 /error 請(qǐng)求,映射到底層的BasicErrorController進(jìn)入默認(rèn)的異常處理機(jī)制。
總結(jié):
當(dāng)發(fā)生異常時(shí),會(huì)被catch。遍歷所有的處理器異常解析器,看誰能夠解析。如果你使用了@ControllerAdvice+@ExceptionHandler配置了全局異常處理,并指定了錯(cuò)誤視圖,那么該異常會(huì)被處理,然后進(jìn)入視圖渲染流程。如果該異常沒能夠被任何處理器異常解析器處理,就會(huì)拋出異常,由Tomcat發(fā)送/error請(qǐng)求,進(jìn)入默認(rèn)的異常處理機(jī)制,也就是開頭說的,沒有配置錯(cuò)誤狀態(tài)碼頁面,則返回默認(rèn)我們常見的默認(rèn)錯(cuò)誤頁。
訪問的是不存在的路徑,此時(shí)不會(huì)發(fā)生異常,經(jīng)過處理器映射,處理器適配調(diào)用仍然返回的是空的ModelAndView,所以無法進(jìn)行視圖渲染。Tomcat仍會(huì)發(fā)送 /error請(qǐng)求,進(jìn)入默認(rèn)的異常處理機(jī)制。
三、默認(rèn)的異常處理機(jī)制
要想弄懂錯(cuò)誤處理原理,首先得看**ErrorMvcAutoConfiguration:這是錯(cuò)誤處理的自動(dòng)配置類**,給容器中添加了下面幾個(gè)非常重要的組件。
ErrorPageCustomizerBasicErrorControllerDefaultErrorViewResolverDefaultErrorAttributes
首先我們看ErrorPageCustomizer 組件,此組件是一個(gè)靜態(tài)內(nèi)部類,位于ErrorMvcAutoConfiguration內(nèi)。它實(shí)現(xiàn)了ErrorPageRegistrar接口,該接口提供了可以用來注冊(cè)ErrorPage的方法。官方將ErrorPage 描述為:簡單的服務(wù)器獨(dú)立的錯(cuò)誤頁面抽象,大致相當(dāng)于web.xml中傳統(tǒng)的元素<error-page>。ErrorPage里包含了狀態(tài)碼、異常、和錯(cuò)誤控制器映射路徑(server.error.path=/error)。也就是說當(dāng)發(fā)生了異常,而且所有的處理器異常解析器都處理不了該異常,Tomcat就會(huì)發(fā)送/error請(qǐng)求映射到BasicErrorController。
static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
//關(guān)于服務(wù)器的一些配置,如端口號(hào),編碼方式等。在這里主要關(guān)注server.error.path
private final ServerProperties properties;
private final DispatcherServletPath dispatcherServletPath;
protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
this.properties = properties;
this.dispatcherServletPath = dispatcherServletPath;
}
//注冊(cè)錯(cuò)誤頁面
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
//ErrorPage里包含了狀態(tài)碼、異常、和錯(cuò)誤控制器映射路徑
ErrorPage errorPage = new ErrorPage(
//this.properties.getError().getPath()獲取的就是server.error.path=/error(默認(rèn))
this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
//注冊(cè)ErrorPage
errorPageRegistry.addErrorPages(errorPage);
}
}
====================DispatcherServletPath接口=================================
public interface DispatcherServletPath {
default String getRelativePath(String path) {
String prefix = getPrefix();
if (!path.startsWith("/")) {
path = "/" + path;
}
return prefix + path;
}
}
下面介紹的就是BasicErrorController。它里面有兩個(gè)重要的方法,正好對(duì)象開頭說的默認(rèn)處理機(jī)制。方法一:如果是瀏覽器請(qǐng)求,則返回HTML響應(yīng)數(shù)據(jù)text/html,方法二:如果是其他客戶端請(qǐng)求,則返回JSON響應(yīng)數(shù)據(jù)。
@Controller
//server.error.path 為空則用error.path, 再為空,再用/error
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
//1、產(chǎn)生html類型的數(shù)據(jù);瀏覽器客戶端發(fā)送的請(qǐng)求來到這個(gè)方法處理
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
//狀態(tài)碼
HttpStatus status = getStatus(request);
//從DefaultErrorAttributes里獲取可以在頁面顯示的數(shù)據(jù)
Map<String, Object> model = Collections
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//調(diào)用父類里的方法,尋找錯(cuò)誤視圖解析器,來解析錯(cuò)誤視圖
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//!??!如果沒有配置具體的狀態(tài)碼錯(cuò)誤頁面或4xx,5xx這種視圖,視圖解析不成功,就會(huì)返回空的ModelAndView對(duì)象。此時(shí)就會(huì)構(gòu)造一個(gè)默認(rèn)的error錯(cuò)誤視圖,通過BeanNameViewResolver視圖解析器,根據(jù)視圖名(error)作為組件id去容器中找到View對(duì)象
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
//2、產(chǎn)生json數(shù)據(jù),其他客戶端來到這個(gè)方法處理
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity<>(status);
}
Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
}
========================AbstractErrorController================================
protected ModelAndView resolveErrorView(HttpServletRequest request,HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
//錯(cuò)誤視圖解析器獲取錯(cuò)誤視圖,返回ModelAndView
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
總結(jié)一下,BasicErrorController主要作用:
處理默認(rèn)/error 路徑的請(qǐng)求
調(diào)用DefaultErrorViewResolver進(jìn)行錯(cuò)誤視圖解析,分為三種情況
1.模板引擎支持解析,就去 /templates/error/下尋找我們配置的 狀態(tài)碼錯(cuò)誤頁面,例如404.html 或4xx.html。
2.模板引擎找不到這個(gè)錯(cuò)誤頁面,就去靜態(tài)資源文件夾【/resources/、/static/、/public/、/META-INF/resources/】下的error文件夾下尋找狀態(tài)碼錯(cuò)誤頁面。
3.靜態(tài)資源文件夾下也找不到,則new ModelAndView("error", model)構(gòu)造一個(gè)默認(rèn)的錯(cuò)誤視圖【就是經(jīng)常見到的 Whitelabel Error Page】。該默認(rèn)的錯(cuò)誤視圖在ErrorMvcAutoConfiguration里已經(jīng)注冊(cè)到容器里了,并且它在容器中的id就是error。后面就會(huì)通過BeanNameViewResolver視圖解析器,根據(jù)視圖邏輯 error,作為組件id去容器中就可以找到默認(rèn)的錯(cuò)誤視圖。
=========================ErrorMvcAutoConfiguration========================================
protected static class WhitelabelErrorViewConfiguration {
private final StaticView defaultErrorView = new StaticView();
//向容器種注冊(cè)默認(rèn)的錯(cuò)誤視圖,id為error
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {
return this.defaultErrorView;
}
}
//可以看到靜態(tài)內(nèi)部類StaticView,進(jìn)行視圖渲染的時(shí)候,構(gòu)造了我們經(jīng)??吹降哪J(rèn)錯(cuò)誤頁面Whitelabel Error Page。
private static class StaticView implements View {
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (response.isCommitted()) {
String message = getMessage(model);
logger.error(message);
return;
}
response.setContentType(TEXT_HTML_UTF8.toString());
StringBuilder builder = new StringBuilder();
Object timestamp = model.get("timestamp");
Object message = model.get("message");
Object trace = model.get("trace");
if (response.getContentType() == null) {
response.setContentType(getContentType());
}
builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
.append("<div id='created'>").append(timestamp).append("</div>")
.append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
.append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
if (message != null) {
builder.append("<div>").append(htmlEscape(message)).append("</div>");
}
if (trace != null) {
builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
}
builder.append("</body></html>");
response.getWriter().append(builder.toString());
}
}
接下來就是介紹 DefaultErrorViewResolver,主要就是進(jìn)行錯(cuò)誤視圖解析。如果發(fā)生錯(cuò)誤,就會(huì)以HTTP的狀態(tài)碼 作為視圖地址,找到真正的錯(cuò)誤頁面。但是注意,首先是精確查找具體的錯(cuò)誤狀態(tài)碼頁面,然后是按照4xx,5xx這種查找。
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
private static final Map<Series, String> SERIES_VIEWS;
static {
Map<Series, String> views = new EnumMap<>(Series.class);
views.put(Series.CLIENT_ERROR, "4xx");
views.put(Series.SERVER_ERROR, "5xx");
SERIES_VIEWS = Collections.unmodifiableMap(views);
}
//解析錯(cuò)誤視圖,要去的錯(cuò)誤頁面
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
//先精確查找錯(cuò)誤視圖
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
//精確查找不到,則查找4xx,5xx這種類型的錯(cuò)誤頁面
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
//真正解析 viewName是狀態(tài)碼
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//?。。。∧J(rèn)SpringBoot可以去找到一個(gè)頁面 error/404,注意定制錯(cuò)誤頁面要放在error文件夾下,如error/4xx.html
String errorViewName = "error/" + viewName;
//模板引擎可以解析這個(gè)頁面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
.getProvider(errorViewName, this.applicationContext);
if (provider != null) {
//模板引擎可用的情況下返回到errorViewName指定的視圖地址
return new ModelAndView(errorViewName, model);
}
//模板引擎不可用,就在靜態(tài)資源文件夾下找errorViewName對(duì)應(yīng)的頁面 error/404.html
return resolveResource(errorViewName, model);
}
//模板引擎不可用,就去靜態(tài)資源文件夾下尋找
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
//這里遍歷的是"classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/"
for (String location : this.resourceProperties.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
if (resource.exists()) {
return new ModelAndView(new HtmlResourceView(resource), model);
}
}
catch (Exception ex) {
}
}
return null;
}
}
最后介紹DefaultErrorAttributes,里面存放了錯(cuò)誤頁面能夠顯示的數(shù)據(jù)。比如狀態(tài)碼、錯(cuò)誤提示、異常消息等。
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
//幫我們?cè)陧撁婀蚕硇畔?
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, requestAttributes);
addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
addPath(errorAttributes, requestAttributes);
return errorAttributes;
}
}
總結(jié):
- 當(dāng)發(fā)生了異常,而且所有的處理器異常解析器都處理不了該異常,
ErrorPageCustomizer就會(huì)生效(定制錯(cuò)誤的響應(yīng)規(guī)則)。Tomcat就會(huì)發(fā)送/error請(qǐng)求,然后被HandlerMapping映射到BasicErrorController處理。 - 解析錯(cuò)誤視圖:前提是配置了4xx.html、5xx.html錯(cuò)誤狀態(tài)碼頁面,去哪個(gè)狀態(tài)碼錯(cuò)誤頁面就由
DefaultErrorViewResolver解析得到。如果沒有配置錯(cuò)誤狀態(tài)碼頁面,就是默認(rèn)的錯(cuò)誤視圖StaticView,它是位于ErrorMvcAutoConfiguration里的一個(gè)靜態(tài)內(nèi)部類,被自動(dòng)注冊(cè)到容器中。后面進(jìn)行視圖渲染的時(shí)候,就是StaticView里的render()方法構(gòu)造了我們經(jīng)??吹降哪J(rèn)錯(cuò)誤頁面【W(wǎng)hitelabel Error Page】。 - 提取數(shù)據(jù):頁面能夠獲取什么數(shù)據(jù)是由
DefaultErrorViewResolver設(shè)置的。
四、自定義異常處理
1、自定義異常處理頁
有模板引擎的情況下
- 沒有模板引擎(模板引擎找不到這個(gè)錯(cuò)誤頁面),靜態(tài)資源文件夾下找。依然要將錯(cuò)誤頁面放在error文件夾下。
- error/狀態(tài)碼.html,就是將錯(cuò)誤頁面命名為
狀態(tài)碼.html放在模板引擎文件夾里面的 error文件夾下;我們可以使用4xx和5xx作為錯(cuò)誤頁面的文件名來匹配這種類型的所有錯(cuò)誤,不過優(yōu)先尋找精確的狀態(tài)碼.html。 - 以上都沒有找到錯(cuò)誤頁面,就是默認(rèn)來到SpringBoot默認(rèn)的錯(cuò)誤提示頁面。
錯(cuò)誤頁面能獲取的信息DefaultErrorAttributes:
- timestamp:時(shí)間戳
- status:狀態(tài)碼
- error:錯(cuò)誤提示
- exception:異常對(duì)象
- message:異常消息
- errors:JSR303數(shù)據(jù)校驗(yàn)的錯(cuò)誤都在這里
2、@ControllerAdvice+@ExceptionHandler處理全局異常
底層是由 ExceptionHandlerExceptionResolver處理器異常解析器支持的
3、@ResponseStatus+自定義異常
底層是由 ResponseStatusExceptionResolver處理器異常解析器支持的,但是它解析完成后,調(diào)用了 **response.sendError(statusCode, resolvedReason);**由tomcat發(fā)送的/error請(qǐng)求,進(jìn)入默認(rèn)異常處理機(jī)制。
Spring底層的異常
如 參數(shù)類型轉(zhuǎn)換異常;由DefaultHandlerExceptionResolver 處理器異常解析器支持的,處理框架底層的異常。但是它解析完成后,調(diào)用了 response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); 由tomcat發(fā)送的/error請(qǐng)求,進(jìn)入默認(rèn)處理機(jī)制。
擴(kuò)展:【可不看】
自定義處理器異常解析器、錯(cuò)誤視圖解析器:
實(shí)現(xiàn) HandlerExceptionResolver接口自定義處理器異常解析器;可以作為默認(rèn)的全局異常處理規(guī)則

實(shí)現(xiàn)ErrorViewResolver自定義錯(cuò)誤視圖解析器
到此這篇關(guān)于SpringBoot的異常處理流程是什么樣的?的文章就介紹到這了,更多相關(guān)SpringBoot異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?I/O?(Input/Output)文件字節(jié)流舉例詳解
Java的輸入輸出流(IO)是用于與外部設(shè)備(如文件、網(wǎng)絡(luò)連接等)進(jìn)行數(shù)據(jù)交互的機(jī)制,下面這篇文章主要給大家介紹了關(guān)于Java?I/O?(Input/Output)文件字節(jié)流的相關(guān)資料,需要的朋友可以參考下2024-08-08
StreamAPI多次消費(fèi)一個(gè)stream代碼實(shí)例
這篇文章主要介紹了StreamAPI多次消費(fèi)一個(gè)stream代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
java密鑰交換算法DH定義與應(yīng)用實(shí)例分析
這篇文章主要介紹了java密鑰交換算法DH定義與應(yīng)用,結(jié)合實(shí)例形式分析了Java密鑰交換算法DH的原理、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-09-09
Java中如何快速構(gòu)建項(xiàng)目腳手架的實(shí)現(xiàn)
這篇文章主要介紹了Java中如何快速構(gòu)建項(xiàng)目腳手架,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
idea中使用maven?archetype新建項(xiàng)目時(shí)卡住問題解決方案
這篇文章主要介紹了idea中使用maven?archetype新建項(xiàng)目時(shí)卡住,解決本問題的方法,就是在maven的runner加上參數(shù)-DarchetypeCatalog=local就可以了,不需要下載xml文件再放到指定目錄,需要的朋友可以參考下2023-08-08
Java中String類常用類型實(shí)例總結(jié)
在我們開發(fā)中經(jīng)常會(huì)用到很多的常用的工具類,這里做一個(gè)總結(jié),下面這篇文章主要給大家介紹了關(guān)于Java中String類常用類型的相關(guān)資料,String類代表字符串,需要的朋友可以參考下2021-12-12

