代码的等价性

本文探讨了代码片段之间的等价性问题,特别是在处理条件语句时的陷阱。以两个不等效的代码片段为例,指出在代码片段2中,如果file1.delete()返回true,后续的file2.delete()和file3.delete()将不会执行,强调编程中应避免此类逻辑错误。

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

代码片段1:

boolean result1 = file1.delete();
boolean result2 = file2.delete();
boolean result3 = file3.delete();
 
if( result1 || result2 || result3)
{
    //do something ...
}


 

代码片段2:

if( file1.delete() || file2.delete() || file3.delete())
{
    //do something ...
}


 

上述两个代码片段是不等效的.在代码片段2,如果file1.delete()返回true,那么后面的file2.delete()file3.delete()将不会执行.在编程中需要避免这种陷阱!!!

 

完整示例如下:

public class LogicTest {
    public void test1() {
        System.out.println("call test1 begin ...");
 
        Logic logic = new Logic();
        boolean result1 = changeA(logic);
        boolean result2 = changeB(logic);
        boolean result3 = changeC(logic);
 
        if (result1 || result2 || result3) {
            System.out.println(logic.getA());
            System.out.println(logic.getB());
            System.out.println(logic.getC());
        }
 
        System.out.println("call test1 end ...");
    }
 
    public void test2() {
        System.out.println("call test2 begin ...");
 
        Logic logic = new Logic();
        if (changeA(logic) || changeB(logic) || changeC(logic)) {
            System.out.println(logic.getA());
            System.out.println(logic.getB());
            System.out.println(logic.getC());
        }
 
        System.out.println("call test2 end ...");
    }
 
    public boolean changeA(Logic logic) {
        logic.setA(5);
        return true;
    }
 
    public boolean changeB(Logic logic) {
        logic.setB(6);
        return true;
    }
 
    public boolean changeC(Logic logic) {
        logic.setC(7);
        return true;
    }
 
    class Logic {
        private int a;
        private int b;
        private int c;
 
        public int getA() {
            return a;
        }
 
        public void setA(int a) {
            this.a = a;
        }
 
        public int getB() {
            return b;
        }
 
        public void setB(int b) {
            this.b = b;
        }
 
        public int getC() {
            return c;
        }
 
        public void setC(int c) {
            this.c = c;
        }
    }
 
    public static void main(String[] args) {
        new LogicTest().test1();
        System.out.println();
        new LogicTest().test2();
    }
}


 

输出结果为:

call test1 begin ...
5
6
7
call test1 end ...
 
call test2 begin ...
5
0
0
call test2 end ...


 

<think>我们正在讨论的是JSP中的表达式:`action="${pageContext.request.contextPath}/login"`用户要求理解这个表达式的功能,并找到等价代码(可能是纯Java代码或者Servlet中的写法)回顾:这个表达式用于动态获取当前Web应用的上下文路径(contextpath),然后拼接上"/login",形成一个完整的URL路径。在JSP中,它通常用于表单的action属性,以确保无论应用部署在什么路径下(如根路径或子路径),都能正确提交到目标URL。在Servlet或Java代码中,我们可以通过HttpServletRequest对象来获取contextpath。因此,等价的Java代码可以这样写:在Servlet中,我们可以通过request.getContextPath()获取上下文路径,然后拼接字符串。例如,如果我们想在Servlet中生成一个链接,我们可以这样:StringloginUrl=request.getContextPath()+"/login";但是,用户的问题中提到了“替换等价代码”,并且是在JSP的上下文中。实际上,在JSP中,我们使用EL表达式(ExpressionLanguage)来简化代码。如果我们不想使用EL表达式,或者在某些不支持EL的环境中,我们可以使用JSP脚本片段(scriptlet)来达到同样的效果,但是不推荐使用脚本片段,因为EL更简洁安全。所以,我们可以用以下两种方式替换:1.使用JSP脚本片段(不推荐,但作为等价代码):action="<%=request.getContextPath()%>/login"2.使用JSTL的c:url标签(推荐):<c:urlvalue="/login"var="loginUrl"/>action="${loginUrl}"注意:第二种方式需要引入JSTL标签库。下面详细解释:方法一:使用JSP脚本片段(scriptlet)-在JSP页面中,我们可以使用<%=%>输出表达式,其中request是JSP内置对象(HttpServletRequest)。-因此,我们可以写成:`action="<%=request.getContextPath()%>/login"`-注意:这种方法虽然等价,但已经过时,因为脚本片段不利于维护,并且可能带来安全问题。方法二:使用JSTL的<c:url>标签-首先在JSP页面顶部引入JSTL核心标签库:`<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>`-然后使用:`<c:urlvalue="/login"/>`它会自动添加上下文路径。-我们可以将其赋值给一个变量,然后在action中使用:<c:urlvalue="/login"var="loginUrl"/><formaction="${loginUrl}"method="post">...</form>-或者直接内联:`<formaction="<c:urlvalue='/login'/>"method="post">`方法三:直接使用EL表达式(和原表达式几乎相同,但原表达式已经使用了EL)-原表达式:`${pageContext.request.contextPath}/login`就是EL表达式。-如果不想写这么长,我们可以使用JSTL的c:url,或者使用EL函数,但EL本身没有提供更短的写法。因此,总结等价代码:-在JSP中,如果不想使用`${pageContext.request.contextPath}`,我们可以使用JSTL的<c:url>标签,它更简洁,并且还能处理URL重写(jsessionid)等问题。-在Servlet中,我们可以使用request.getContextPath()来获取,然后拼接字符串。但是用户的问题是在JSP页面中,所以主要考虑在JSP中的替换。注意:在纯HTML文件中,无法使用JSP或EL,所以需要其他方法(比如使用base标签,或者通过JavaScript动态设置),但用户没有提到纯HTML。根据用户提供的引用[1],里面有一个JSP页面使用了`${msg}`,说明该JSP使用了EL,所以我们可以继续使用EL,但用户可能想了解其他方式。因此,我们给出两种替换方案(脚本片段和JSTL)。代码示例:1.使用脚本片段(不推荐):```jsp<formaction="<%=request.getContextPath()%>/login"method="post"><!--表单内容--></form>```2.使用JSTL(推荐):```jsp<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>...<formaction="<c:urlvalue='/login'/>"method="post"><!--表单内容--></form>```3.或者使用JSTL变量:```jsp<c:urlvalue="/login"var="loginUrl"/><formaction="${loginUrl}"method="post"><!--表单内容--></form>```注意:JSTL的<c:url>会在需要的时候自动添加jsessionid(当客户端禁用cookie时),所以更安全。因此,如果用户希望替换掉`${pageContext.request.contextPath}/login`,推荐使用JSTL的<c:url>方式。另外,用户提供的引用[2]是一个Github项目链接,可能与问题无关,但我们可以忽略。最后,关于用户提到的“javajsppagecontextrequestcontextpathloginequivalentcode”,我们已经给出了答案。现在,我们生成相关问题。</think>### `${pageContext.request.contextPath}/login` 的等价 Java/JSP 代码 在 JSP 页面中,表达式 `action="${pageContext.request.contextPath}/login"` 可通过以下方式实现等价功能: #### 1. **使用 JSP 脚本片段 (Scriptlet)** ```jsp <form action="<%= request.getContextPath() %>/login" method="post"> ``` - **原理**:直接调用 `HttpServletRequest.getContextPath()` 方法获取上下文路径 - **优点**:兼容旧版 JSP 规范 (Servlet 2.4 之前) - **缺点**:混合 Java 与 HTML 代码,不推荐在新项目中使用[^1] #### 2. **使用 JSTL `<c:url>` 标签 (推荐)** ```jsp <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <form action="<c:url value='/login'/>" method="post"> ``` - **原理**:JSTL 标签自动添加上下文路径 - **优点**: - 自动处理 URL 重写 (如 `jsessionid`) - 支持相对/绝对路径智能转换 - 符合现代 JSP 开发规范[^1] #### 3. **后端 Servlet 中动态生成路径** ```java // 在 Servlet 中设置路径属性 protected void doGet(HttpServletRequest request, HttpServletResponse response) { String loginPath = request.getContextPath() + "/login"; request.setAttribute("loginUrl", loginPath); } ``` ```jsp <!-- JSP 中使用 EL 获取 --> <form action="${loginUrl}" method="post"> ``` - **适用场景**:路径需在后端逻辑中动态计算时 #### 4. **JavaScript 动态设置 (纯前端方案)** ```jsp <script> document.addEventListener("DOMContentLoaded", () => { const form = document.querySelector("form"); form.action = "<%= request.getContextPath() %>/login"; }); </script> ``` - **适用场景**:无法使用 JSTL 或 EL 的纯 HTML 环境 ### 方案对比 | 方法 | 可维护性 | 兼容性 | 推荐度 | 特点 | |---------------------|----------|--------------|--------|--------------------------| | JSTL `<c:url>` | ★★★★★ | Servlet 3.0+ | ★★★★★ | 自动处理编码和会话ID | | EL + 后端设置 | ★★★★☆ | Servlet 2.5+ | ★★★★☆ | 前后端分离 | | JSP Scriptlet | ★★☆☆☆ | Servlet 2.3+ | ★★☆☆☆ | 遗留系统兼容 | | JavaScript 动态设置 | ★★★☆☆ | 所有浏览器 | ★★★☆☆ | 无服务器依赖 | ### 最佳实践建议 1. **现代项目首选 JSTL**: ```jsp <c:url value="/login" var="loginUrl"/> <form action="${loginUrl}" method="post"> ``` 2. **Spring MVC 项目专用方案**: ```jsp <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <form action="<spring:url value='/login'/>"> ``` Spring 的 `<spring:url>` 提供额外的路径处理功能[^2] 3. **修复 EL 不生效的问题**: 在 `web.xml` 中启用 EL: ```xml <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>false</el-ignored> </jsp-property-group> </jsp-config> ``` > 关键点:所有方案的核心都是通过 `HttpServletRequest.getContextPath()` 动态获取部署路径,确保应用在不同环境(根目录/子路径)下的可移植性[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值