# In short

No the two clauses are not at all the same.  They have a different nature regardless of how you enforce them. And both can be infringed separately. Numerous counter-examples invalidate the claim about these being the same thing.  

# More details

## On LSP, contracts and exceptions (the theory)

LSP is about promises made in a **contract** and not about implementation and exceptions. The preconditions and post conditions do not even need to be implemented by the type and its subtype.  Therefore, here a very important distinction:  

* **preconditions** is about conditions that need to be **fulfilled before the an operation is performed**.  If you call the operation but these conditions are not met, it doesn't mean that you have to throw exceptions. It just means that the promises of that operation (invariants, post conditions) are not guaranteed. 
* **postconditions** is about conditions that must be **guaranteed  after the operation is performed**, provided the preconditions were initially met.  If they are not fulfilled, there's something wrong in the code.  

Adding checks and exceptions inside the type's operations, or outside, in the code that uses the type, is defensive programming. It helps sometimes to deduce the contract, but not always. For example, whenever there is a divide in some formula, you may find preconditions that must be fulfilled to avoid the divide by zero to happen, even if you don't explicitly throw. 

By the way, depending how you design and document contracts,  an exception could even be a promised behavior of the contract instead of a failed pre/post-condition(). See for example the following contract that would make your subtype LSP compliant:  

> Task::Close() ensures that the task is in a closed state if closing is possible or that an exception TaskCannotBeClosed is thrown.     

 

## Hypothetical counter example (the practice)

But enough theory.  Now a counter-example, that uses exceptions for pre and post conditions like you did.  Take the following pseudo-code, which has more distinct pre and post conditions. **Please ignore all the other design and style issues** (I would of course design this very differently, it's just to illustrate the case): 

    class Transaction {
      ...
      Money sellProduct (Customer c, Product p, Quantity q) {
           
        if (c.age()<12) // precondition: Customer is aged 12+ 
          throw CustomerTooYoung;
 
        ... // do something 

        if (valueCashedIn < Money(0.00)) // postcondition: amount cashed-in is >=0
          throw InternalErrorOnValue;
        return valueCashedIn ; 
      }
      ...
    }

Here a LSP infringement that strengthens the precondition but leaves post condition unchanged:  

    class TransactionDangerousGoods extends Transaction {
      Money sellProduct (Customer c, Product p, Quantity q) {
           
      if (c.age()<18) // precondition: Customer is aged 18+ 
        throw CustomerTooYoung;
 
      ... do something more specific 

      // keep same postcondition check as before
      }
      ...
    } 
   
Here another LSP infringement on post condition only and that completely misuses the design:  

    class Takeback  extends Transaction {
      Money sellProduct (Customer c, Product p, Quantity q) {
           
        // no precondition, weakens precondition, is ok.   
 
        ... do something to take the product and reimburse customer  

        // no postcondition, weakens postcondition ;
          return valueCashedIn ;  // negative as it is a reimbursement 
        }
      ...
    } 
 
Hence, we see that strengthening precondition and weakening post condition can in many cases be very different