Java异常详解_动力节点Java学院整理

什么是异常?

异常是Java语言中的一部分,它代表程序中由各种原因引起的“不正常”因素。 那么在程序中什么样的情况才算不正常呢? 我认为可以这样定义:如果出现了这么一种情况,它打断了程序期望的执行流程,改变了控制流的方向(包括让JVM停掉),那么就可以认为发生了不正常情况,也就是引发了异常。举个例子显而易见的例子:

FileOutputStream out = null;
try {
  out = new FileOutputStream("abc.text");
  out.write(1);
  System.out.println("写入成功");
} catch (FileNotFoundException e) { 

  System.out.println("要写入的文件不存在");
  e.printStackTrace(); 

} catch (IOException e) { 

  System.out.println("发生了IO错误");
  e.printStackTrace(); 

}finally{
  if(out != null){
    try {
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
} 

我调用FileOutputStream.write(int)方法期望向一个文件写入一个字节的数据,如果在写入时发生了IO错误, 那么就发生了“不正常情况”,也就是抛出IOException,进而程序的控制流发生了改变,本来如果写入成功的话, 会执行FileOutputStream.write(int)下一句代码, 现在发生了异常, 那么程序要跳到IOException对应的catch块中,去处理这个异常情况。

异常体系和分类

Java以面向对象的方式来管理异常情况,也就是说,Java程序执行时遇到的各种问题都被封装成了对象,并且这些对象之间具有继承关系。java中的让人不爽的“不正常情况”可以分为两种,一种叫做Error,一种是在程序中到处可见的Exception,而他们都继承自Throwable。Exception又分为编译时受检查异常(Checked Exception)和运行时异常(RuntimeException)。如下图所示(该图片来源于网络):

一般情况下,Error代表虚拟机在执行程序时遇到严重问题,不能再回复执行了,这属于重大事故,虚拟机要挂掉的,一句话概括就是“这病没得治,等死就行了”。那么打开JDK的文档,列举几种Error:

VirtualMachineError: 当 Java 虚拟机崩溃或用尽了它继续操作所需的资源时,抛出该错误。

ClassFormatError:当 Java 虚拟机试图读取类文件并确定该文件存在格式错误或无法解释为类文件时,抛出该错误。

NoClassDefFoundError:当 Java 虚拟机或 ClassLoader 实例试图在类的定义中加载,但无法找到该类的定义时,抛出此异常。

而相对于Error,Exception是java程序中遇到的“不那么严重”的问题,这种问题是可以处理的,当处理了这个问题后,程序还可以继续执行。一句话概括,“这是病,得治,这病是可以治好的”。

Exception就比较常见了,随便举几个例子。当创建文件输入流时, 发现文件不存在,那么抛出FileNotFoundException,但是异常可以处理,没法读文件,并不会在很大长度上影响整个程序的执行,毕竟不能读文件,程序还可以执行其他逻辑。下面举一个趣味性的示例:

public class Travel {
  private static int power = 100;
  private static boolean bridgeIsOk = true;
  public static void main(String[] args) {
    //描述一下坐火车旅游的过程
    System.out.println("从济南出发, 到北京旅游");
    System.out.println("列车开到德州");
    //中途给妈妈打个电话
    try{
      telToMom();
    }catch(BatteryDiedException e){
      System.out.println("换一块电池, 继续旅程");
    }
    //桥断了
    if(!bridgeIsOk){
      System.out.println("旅程结束");
      throw new BridgeBreakError("桥断了,列车停止运行");
    }
    System.out.println("到北京站,下车");
    //下雨了
    try{
      throw new RainException("下雨了");
    }catch(RainException e){
      System.out.println("撑起准备的雨伞, 继续旅程");
    }
  }
  private static void telToMom() throws BatteryDiedException{
    if(power == 0){ //手机电量为0
      System.out.println("手机没电了");
      throw new BatteryDiedException("手机没电了");
    }
    System.out.println("给妈妈打电话");
  }
  static class BatteryDiedException extends Exception{
    public BatteryDiedException(String msg){
      super(msg);
    }
  }
  static class BridgeBreakError extends Error{
    public BridgeBreakError(String msg){
      super(msg);
    }
  }
  static class RainException extends Exception{
    public RainException(String msg){
      super(msg);
    }
  }
} 

上面的代码描述了一次旅行, 如果在旅途中给妈妈打电话,发现手机没电了, 抛出BatteryDiedException,但是这种异常是可以应付的,直接换一块准备的备用电池就OK了,下了车之后,天下雨了,抛出RainException,这种异常也可以应付,因为提前准备了雨伞。这两种情况都是可以恢复的,遇到之后,只需做一定的处理,旅程还能继续。如果在途中遇到桥断裂的情况,那么列车必须停止运行,这次旅行就泡汤了,也就是说已经不能从这种恶劣情况中恢复过来,所以直接抛出BridgeBreakError。

编译时受检查异常和运行时异常

那么再说一下编译时受检查异常和运行时异常。回顾一下异常的定义:程序在执行时遇到的不正常情况。那么既然是运行时遇到的问题,怎么还有一个编译时受检查异常呢?其实编译时根本不会发生异常,只会在语法错误的情况下编译失败,但是这和异常是不相关的概念。异常只是运行时的行为。那么编译时受检查异常又是一个什么概念呢?要理解受检查异常存在的意义,那么必须明确编码者所处的位置,也可以说编码者的角色, 即:我是功能的具体实现者, 还是功能的使用者,也可以说,我是方法的编写者还是已有方法的调用者。如果我是方法的实现者,我在编码时发现可能会出现异常,那么首先我要明确,这个可能出现的异常我能不能自己处理,如果能自己处理, 那么就在方法内部自己处理掉,如果不能自己处理,那么通知方法的调用者处理。举例说明:

public static Class<?> forName(String className)
      throws ClassNotFoundException {
  return forName0(className, true, ClassLoader.getCallerClassLoader());
} 

上面的代码是JDK中Class类的forName()方法。作为JDK类库的作者,在写这个方法的时候,可能会出现异常, 也就是类加载不到。但是他不知道如何处理这个情况,因为他不知道调用这个方法的用户是加载的什么类,可能是一个非常重要的类, 加载不成的话程序就只能停掉,也可能是一个不那么重要的类,加载不到也没有严重影响。所以,如何处理这个情况,必须是由用户决定。方法后面的throws ClassNotFoundException的意义是:这个方法可能出现ClassNotFoundException,你如果调用了这个方法,那么必须做好防范措施(用try-catch处理这个异常,或者再向上抛出)。如果站在方法使用者的角度,我调用这个方法,如果出现异常,我可以提前准备好解决方案:

try {
  Class clazz = Class.forName("com.bjpowernode.Person");
} catch (ClassNotFoundException e) { 

  System.out.println("Person类加载失败");
  System.exit(0);
  e.printStackTrace();
}

Person类是一个非常中要的类,必须加载成功才能继续执行。如果加载失败, 只能让程序停掉,并且打印出日志。这样的话,程序员可以在其他地方确保这个类必须是可加载的。
所以,可以把编译时受检查异常看做一种错误预警机制:这个错误可能发生, 但也可能不发生,但是如果你想使用这个功能的话,必须做好处理措施,可以使用try-catch处理异常, 也可以抛向更高层。

说完了编译时受检查异常,那么在谈运行时异常, 所有运行时异常的顶层父类都是RuntimeException, RuntimeException也是继承自Exception的。下面是JDK文档中对运行时异常的解释。

1.RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。

3.可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。

也就是说, 如果你在方法中抛出了运行时异常或者其子类,那么可以不必在方法上声明会抛出异常,所以调用这个方法的调用者也就不必在使用的时候做预防措施。那么在异常发生的时候,由于没有处理措施,那么只能让虚拟机停掉,也就是说这种异常一般不需要提前预防。那么什么时候使用运行时异常呢?可以这样认为:如果发生了这样一个异常时,让程序停掉是合理的,那么这种情况就适合使用运行时异常。

还是以上面旅行的例子做一个说明。如果手机在旅途没电了,那么预防这种情况是有意义的,因为换了电池之后还可以继续旅行;突然下雨这种情况也可预防,并且预防这种情况是有意义的,因为打起伞来同样可以继续前进。那么,如果如果在旅途中病了,并且病的还很厉害,那么再预防这种情况对整个旅程来说就没有什么意义了,因为旅程必须终止(看病要紧)。所以直接抛出一个运行时异常让旅程终止。如下:

private static boolean isSick = true;
public static void main(String[] args) {
  if(isSick){
    System.out.println("生病了,旅途中止");
    throw new SickException("病了");
  }
}
private static class SickException extends RuntimeException{
  public SickException(String msg){
    super(msg);
  }
} 

一般来说,运行时异常非常适合处理编程错误,那么什么是编程错误呢?可以认为是程序员写的代码有问题,必须修改程序才能解决问题。看一下JDK中的两个RuntimeException的例子。

IllegalArgumentException:如果用户(方法的调用者)传递的参数不对,那么就会抛出非法参数异常,然后让程序停掉,如果想让程序正确的运行,必须修改调用方式,传递一个正确的参数。如下:

public static void main(String[] args) {
  caculateSalary(3);
} 

/**
 * 计算一个月的薪资
 * @param month 月份
 */
public static void caculateSalary(int month){ 

  //如果参数错误, 抛出非法参数异常
  if(month < 1 || month > 12){
    throw new IllegalArgumentException();
  }
} 

private static void caculateSalaryInner(int month){
  //计算薪资 ...
} 

NullPointerException:如果调用一个方法的对象为null,那么在调用的时候会抛出空指针异常。如果要避免的话,就要修改程序,确保调用方法的对象不为空。

ClassCastException:如果在进行类型转换时,指定了错误的目标类型,那么会抛出类型转换异常。如果要避免的话,要修改代码,以确保指定了正确的要转换的目标类型。

虽然RuntimeException一般用于表示编程错误,在抛出运行时异常时让程序停掉,对代码做一定的改正以让程序可以再次正确运行, 但是要注意到,运行时异常是可以捕获的,捕获之后做出处理后,程序可以恢复执行:

public static void main(String[] args) {
  doSomething();
}
public static void doSomething(){
  Object obj = null;
  try { //运行时异常也是可以捕获的
    obj.toString();
  } catch (RuntimeException e) {
    System.out.println("抛出了运行时异常, 异常的具体类型:" + e.getClass().getName());
  }
} 

打印结果为: 抛出了运行时异常, 异常的具体类型:java.lang.NullPointerException

另外,运行时异常也可以在方法上声明抛出,但是如果方法上声明的是运行时异常,那么方法的调用者可以选择处理, 也可以选择不处理。如果不处理的话,程序会终止,如果捕获后做出处理,程序可以恢复运行:

public static void main(String[] args) {
  doSomething();  //不必处理方法声明抛出的运行时异常
} 

public static void doSomething() throws RuntimeException{ 

  throw new RuntimeException();
} 

虽然运行时异常可以在方法上声明抛出,也可以被捕获,但是一般情况下我们不会这么做。因为运行时异常一般用于表示编程错误,出现异常时让程序停掉是合理的。对运行时异常进行捕获和声明抛出没有多大的意义。比如捕获了空指针异常,虽然进行了处理以让程序不至于崩溃,但是空对象要调用的方法,根本就没有调用成功,这是不合理的。

如何合理使用异常

上面介绍了异常的定义和分类,也提到了一些异常的使用原则。现在总结一下到底应该如何使用异常:

1 重大的错误使用Error。一般Error用于表示系统级别的或虚拟机层面上的错误,在编程中很少使用。

2 有必要预防,并且处理后可以让程序恢复执行的情况使用编译时受检查异常。

3 编程错误使用运行时异常。

4 如果方法自己可以处理异常,那么可以选择自己处理异常,如果方法不知道如何处理异常,那么抛给高层的方法调用者。

5 方法声明抛向高层的异常,必须是对高层有意义并且高层能够理解的异常。

下面再举一个趣味性的例子。

老板派员工出去执行一项任务,在这个过程中有两个角色,员工是低层被调用者,老板是高层调用者。在这个过程中可能出现这么几种情况。

1 老板让员工出去执行一项任务, 那么必须得给拨款(没钱干不成事嘛)。那么如果老板没给钱,或者给的钱不够,那么员工可以选择停止执行。这属于编程错误,要求老板必须给足够的钱才能继续运行。这种情况使用运行时异常表示。

2 到了目的地后,要去办公地点,发现迷路了(可能方向感不好,转向了),找不到公交车的站牌了。这个错误自己完全可以解决,打个车就可以了。并且不能抛给老板,如果抛给老板,那么就等着被炒鱿鱼吧。老板每天很忙,他会这样认为:这员工太操蛋了,这点事都办不成。所以这是个受检查异常,并且适合在内部解决。

3 出差在外,加班太辛苦,在干到一半的时候,累病了。这就是比较严重的情况了,自己不能很好地解决(得去医院)。这也是可以预见的异常,毕竟人都会得病嘛。这也属于受检查异常,自己不能解决,得抛向高层(老板)。但是应该怎样给老板说呢?不能给老板说“老板,我病了”,如果这样给老板说的话,老板会一头雾水:“病了去医院啊, 我又不是医生”。那么怎么给老板说呢?直接告诉老板任务不能完成就行了,当然可以说明为什么不能完成的原因(生病了)。这样的话,老板就可以做出一些处理,可以另外再拍一个人去交接任务,也可以决定暂停任务。所以,抛向高层的异常,必须是对高层有意义并且高层能够理解的异常。

下面用代码描述这个过程:

public class DoWork {
  public static class Boss{  //老板
    private Employee emp; //员工对象
    public Boss(Employee emp){
      this.emp = emp;
    }
    public void doWork(){
      try {
        emp.doWork();  //老板委托员工外出执行任务,给员工块钱的经费
      } catch (TaskCannotCompleteException e) {  //任务无法完成
        System.out.println("派出另一个员工去完成任务");
      }
    }
  }
  public static class Employee{  //员工
    //执行任务,可能不能完成任务
    public void doWork(float money) throws TaskCannotCompleteException{
      //
      if(money < ){  //经费太少,无法执行任务
        throw new MoneyNotEnoughException();
      }
      //
      try {
        goToWorkPlace();
      } catch (CannotFindBusException e) { //在去工作地点时找不到公交车
        System.out.println("打车去");
      }
      //
      try {
        workDayAndNight();
      } catch (TiredToSickException e) { //累病了
        //告诉老板,任务无法完成
        throw new TaskCannotCompleteException();
      }
    }
    //在去工作地点时可能找不到公交车
    private void goToWorkPlace() throws CannotFindBusException{
      //throw new CannotFindBusException();
    }
    //没天没夜的干活, 可能会累病
    private void workDayAndNight() throws TiredToSickException{
      //throw new TiredToSickException();
    }
  }
  //找不到公交车异常
  public static class CannotFindBusException extends Exception{}
  //经费不足异常
  public static class MoneyNotEnoughException extends RuntimeException{}
  //累病异常
  public static class TiredToSickException extends Exception{}
  //任务无法完成异常
  public static class TaskCannotCompleteException extends Exception{}
  public static void main(String[] args) {
    Boss boss = new Boss(new Employee());
    boss.doWork();
  }
} 
(0)

相关推荐

  • java 解决异常 2 字节的 UTF-8 序列的字节2 无效的问题

    java 解决异常 2 字节的 UTF-8 序列的字节 2 无效的问题 最近做项目,遇到异常 2 字节的 UTF-8 序列的字节 2 无效的问题,上网找了下资料,这里记录下解决方法,有遇到同样问题的大家,可以看下 详细异常: 十二月 08, 2015 7:16:55 下午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet [jsp] in context with path

  • Java常见内存溢出异常分析与解决

    Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆内存分为了三部分,新生代,老年代,持久带,其中持久带实现了规范中规定的方法区,而内存模型中不同的部分都会出现相应的OutOfMemoryError错误,接下来我们就分开来讨论一下.java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都出于以下原因: JVM内存过小.程序不严密,产生了过多的垃圾. 导致OutOfMemor

  • Java 常见异常(Runtime Exception )详细介绍并总结

    本文重在Java中异常机制的一些概念.写本文的目的在于方便我很长时间后若是忘了这些东西可以通过这篇文章迅速回忆起来. 1. 异常机制 1.1 异常机制是指当程序出现错误后,程序如何处理.具体来说,异常机制提供了程序退出的安全通道.当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器. 1.2 传统的处理异常的办法是,函数返回一个特殊的结果来表示出现异常(通常这个特殊结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果.这样做有如下的弊端:例如函数返回-1代表出现异常

  • 浅谈java异常处理之空指针异常

    听老师说,在以后的学习中大部分的异常都是空指针异常.所以抽点打游戏的时间来查询一下什么是空指针异常 一:空指针异常产生的主要原因如下: (1)当一个对象不存在时又调用其方法会产生异常obj.method() // obj对象不存在 (2)当访问或修改一个对象不存在的字段时会产生异常obj.method() // method方法不存在 (3)字符串变量未初始化: (4)接口类型的对象没有用具体的类初始化,比如: List lt:会报错 List lt = new ArrayList():则不会报

  • java实现系统捕获异常发送邮件案例

    在实际运用中,比如你淘宝购物,申请退款,这时你在邮箱中看到退款邮件,或者你注册某个账号,申请验证邮箱通知等等,这些都是邮件发送,这里将介绍下系统捕获异常发送邮件案例. 准备工作: eclipse4.5 64位 jdk1.7 64位 邮件发送所需jar: fastjson-1.1.24.jar,javax.mail-1.5.6.jar 类Developer: 枚举类型,发送邮件人姓名和邮箱地址 package mail; /** * @class:Developer *@descript:枚举类型

  • 浅谈java异常链与异常丢失

    1.在java的构造方法中提供了 异常链.. 也就是我们可以通过构造方法不断的将 异常串联成一个异常链... 之所以需要异常连,是因为处于代码的可理解性,以及阅读和程序的可维护性... 我们知道我们每抛出一个异常都需要进行try catch ...那么岂不是代码很臃肿... 我们如果可以将异常串联成一个异常连,然后我们只捕获我们的包装 异常,我们知道 RuntimeException 以及其派生类可以不进行try catch 而被jvm自动捕获并处理.. 当然了我们可以自己定义自己的异常类从Ru

  • 浅谈java中异常抛出后代码是否会继续执行

    问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element){ if(size >= elements.length) { throw new RuntimeException("顺序表已满,无法添加"); //return; //需要吗? } .... } 为了回答这个问题,我编写了几段代码测试了一下,结果如下: //代码1 public

  • java异常和错误类总结(必看篇)

    java异常和错误类总结 最近由于考试和以前的面试经常会遇到java当中异常类的继承层次的问题,弄得非常头大,因为java的异常实在是有点多,很难记下来,今天正好查了一些资料整理下来,希望对自己和大家有点帮助.最开始的时候习惯用笔记本(手写的纸质的本子)记笔记,后来发现查阅的时候不是很方便,而且速度比较慢.后来改用notepad开始记,感觉效果挺棒,简单易用,没有花哨的东西.但是也有它的缺点,比如版式的整理,不能加入一些图片(往往图片特别是一些大纲是非常好的记忆学习方法)等等,于是尝试用mark

  • Java异常详解_动力节点Java学院整理

    什么是异常? 异常是Java语言中的一部分,它代表程序中由各种原因引起的"不正常"因素. 那么在程序中什么样的情况才算不正常呢? 我认为可以这样定义:如果出现了这么一种情况,它打断了程序期望的执行流程,改变了控制流的方向(包括让JVM停掉),那么就可以认为发生了不正常情况,也就是引发了异常.举个例子显而易见的例子: FileOutputStream out = null; try { out = new FileOutputStream("abc.text"); o

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java ThreadLocal详解_动力节点Java学院整理

    一.对ThreadLocal的理解 ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多.可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量. 这句话从字面上看起来很容易理解,但是真正理解并不是那么容易. 我们还是先来看一个例子: class ConnectionManager { private static Connection connect = null; public static

  • Java Runtime类详解_动力节点Java学院整理

    一.概述 Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用.一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为. 当不被信任的代码调用任何Runtime方法时,常常会引起SecurityExc

  • Java System类详解_动力节点Java学院整理

    System类是jdk提供的一个工具类,有final修饰,不可继承,由名字可以看出来,其中的操作多数和系统相关.其功能主要如下: • 标准输入输出,如out.in.err • 外部定义的属性和环境变量的访问,如getenv()/setenv()和getProperties()/setProperties() • 加载文件和类库的方法,如load()和loadLibrary(). • 一个快速拷贝数组的方法:arraycopy() • 一些jvm操作,如gc().runFinalization()

  • Java Scaner类详解_动力节点Java学院整理

    Java.util.Scanner是Java5.0的新特征,主要功能是简化文本扫描.这个类最实用的地方表现在获取控制台输入,其他的功能都很鸡肋,尽管Java API文档中列举了大量的API方法,但是都不怎么地. 一.扫描控制台输入  这个例子是常常会用到,但是如果没有Scanner,你写写就知道多难受了. 当通过new Scanner(System.in)创建一个Scanner,控制台会一直等待输入,直到敲回车键结束,把所输入的内容传给Scanner,作为扫描对象.如果要获取输入的内容,则只需要

  • web.xml详解_动力节点Java学院整理

    一.            Web.xml详解: (一)  web.xml加载过程(步骤) 首先简单说一下,web.xml的加载过程. 当我们去启动一个WEB项目时,容器包括(JBoss.Tomcat等)首先会读取项目web.xml配置文件里的配置,当这一步骤没有出错并且完成之后,项目才能正常地被启动起来.   启动WEB项目的时候,容器首先会去它的配置文件web.xml读取两个节点: <listener></listener>和<context-param><

  • HTTP协议详解_动力节点Java学院整理

    一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议. HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议.

  • Java class文件格式之属性详解_动力节点java学院整理

    Code属性 code属性是方法的一个最重要的属性. 因为它里面存放的是方法的字节码指令, 除此之外还存放了和操作数栈,局部变量相关的信息. 所有不是抽象的方法, 都必须在method_info中的attributes中有一个Code属性.下面是Code属性的结构, 为了更直观的展示Code属性和method_info的包含关系, 特意画出了method_info: 下面依次介绍code属性中的各个部分. attribute_name_index指向常量池中的一个CONSTANT_Utf8_in

  • Apache和Nginx的优缺点详解_动力节点Java学院整理

    Apache和Nginx比较 功能对比 Nginx和Apache一样,都是HTTP服务器软件,在功能实现上都采用模块化结构设计,都支持通用的语言接口,如PHP.Perl.Python等,同时还支持正向和反向代理.虚拟主机.URL重写.压缩传输.SSL加密传输等. 在功能实现上,Apache的所有模块都支持动.静态编译,而Nginx模块都是静态编译的, 对FastCGI的支持,Apache对Fcgi的支持不好,而Nginx对Fcgi的支持非常好: 在处理连接方式上,Nginx支持epoll,而Ap

随机推荐