Выдавание исключения в Java

1128 Я думаю, что здесь вам не хватает концепции React. Вы должны держать свое состояние высоко в иерархии компонентов, если вам это нужно ниже.

В этом примере у вас есть что-то в компоненте Main, что вам нужно в компоненте-брате Header. Это означает, что у вас должен быть родительский компонент, который передает эту информацию им.

Например, у вас может быть компонент App, который каким-то образом принимает JSON и сохраняет его в своем состоянии вместе с другой информацией о продукте:

// App.js
import React, { Component } from 'react'
import PRODUCTS from '../plist.json'

class App extends Component {

  state = {
    // here we are preparing the state copying all the
    // information of a product plus a quantity property set to 0
    products: PRODUCTS.map(p => ({ ...p, quantity: 0 }))
  }

  render() {
    return (
      <>
        {/* here we should render the two components who needs data */}
        <Footer />
      </>
    )
  }

}

В методе render мы можем отобразить три исходные компоненты, но с некоторыми изменениями ...

Во-первых, Header требует общего количества и общей цены. Одна из лучших практик React говорит нам, что все, что можно вычислить из состояния, должно быть за его пределами. В этом случае нам не нужно сохранять эти две величины в состоянии, потому что мы можем легко вычислить их:

// in App class definition

...

totalQuantity = () =>
  this.state.products.reduce(
    (sum, product) => sum + product.quantity,
    0
  )

totalPrice = () =>
  this.state.products.reduce(
    (sum, product) => sum + product.quantity * product.price,
    0
  )

...

Имея возможность вычислить эти значения, мы добавляем рендеринг Header компонент для метода рендеринга App:

// in App class definition

...

render() {
  return (
    <>
      <Header quantity={ this.totalQuantity() } 
              price={ this.totalPrice() }
      />
      {/* here we should render the Main component */}
      <Footer />
    </>
  )
}

...

Конечно, вам придется изменить способ рендеринга этих значений в компоненте Header:

// Header component, render() method
// remember to apply some formatting for currency etc.
<span className={ this.getClass() }>
  Total Quantity: { this.props.quantity }
  Total Price: { this.props.price } 
</span>

Сейчас Давайте немного переосмыслим компонент Main. Он делает две вещи:

  • отображает список продуктов;
  • обрабатывает увеличение / уменьшение количества;

Давайте добавим Main в метод визуализации и затем поработаем над этими функциями:

// in App class definition

...

render() {
  return (
    <>
      <Header quantity={ this.totalQuantity() } 
              price={ this.totalPrice() }
      />
      <Main products={ this.state.products }
            onIncrement={ this.handleIncrement }
            onDecrement={ this.handleDecrement }
      />
      {/* here we should render the Footer component */}
    </>
  )
}

...

В компоненте Main нам нужно изменить способ рендеринга продуктов, потому что мы больше не читаем JSON, но мы можем использовать данные, предоставленные App. Кроме того, мы должны иметь возможность передавать события увеличения и уменьшения:

// Main

...

render () {return ({this.props.products.map ((product, index) => this.props.onIncrement (index)} onDecrement = {() => this.props.onDecrement (index)} />)})}

...

Внизу в компоненте Product нам больше не нужно внутреннее состояние, потому что все, что нам нужно, предоставляется в качестве реквизита, поэтому он может быть компонентом без состояния:

const Product = ({
  image, 
  url, 
  name, 
  price, 
  description, 
  onIncrement, 
  quantity,
  onDecrement
}) => (
  <div className="col-md-4 ml-auto">
    <img className="productpic" 
         src={ require(`./images/${image}`) }
         alt="Product"
    />
    <h2 className="display-6">
      <a href="{url}">
        { name }
      </a>
    </h2>
    <p className="h5 price">
      { price }
    </p>
    <p className="info">
      { description }
    </p>
    <div className="counter">
      <button className="btn btn-info"
              onClick={ onIncrement }>
        +
      </button>
      <div className="count">
        { quantity }
      </div>
      <button className="btn btn-info"
              onClick={ onDecrement }>
        -
      </button>
    </div>
  </div>
)

Для завершения этого Поведение, нам нужно обработать приращение и уменьшение в компоненте App, чтобы обновить состояние и распространить обновленную информацию до Header (количество и общее количество) и Main.

// in App

...

handleIncrement = index =>
  this.setState(prevState => ({
    products: [
       ...prevState.products,
       [index]: {
          ...prevState.products[index],
          quantity: prevState.products[index].quantity + 1
       }
    ]
  }))

handleDecrement = index =>
  this.setState(prevState => ({
    products: [
       ...prevState.products,
       [index]: {
          ...prevState.products[index],
          quantity: prevState.products[index].quantity - 1
       }
    ]
  }))

...

Мы почти закончили, в вашем index.js рендеринге только компонент App:

import React from "react";
import ReactDOM from "react-dom";
import App from "./components/app";
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';


ReactDOM.render(<App />, document.getElementById("root"));
5
задан user42155 9 February 2009 в 14:47
поделиться

11 ответов

Исключения должны быть выданы из метода, когда тот метод неспособен к разрешению исключения самостоятельно.

Например, a FileNotFoundException брошен от new FileInputStream(new File(filename)) потому что сам FileInputStream не может обработать случай, где файл отсутствует; то исключение должно быть выдано так, приложение конечного пользователя может решить проблему.

Существуют некоторые случаи, где исключения могли быть обработаны в рамках метода. Например, метод модели Document, бросающий a BadLocationException мог быть обработан в рамках достаточно интеллектуального метода. В зависимости от проблемы или исключение может быть обработано или повторно брошено.

(Так или иначе я утверждал бы, что, выдавая исключение из блока try-catch, таким образом, блок выгоды может быть выполнен, представляет действительно плохой логический поток),

21
ответ дан 18 December 2019 в 05:17
поделиться

Не первый способ обработать исключения делает точно это (механизм выгоды броска попытки)? Я имею в виду, это выдает исключение и ловит его в том же методе.

Это не "способ обработать исключения" - это - чрезвычайная ерунда. Смысл исключений должен позволить другому методу, стек вызовов обрабатывает его. Если Вы собираетесь обработать условие в рамках того же метода, нет никакого смысла в использовании исключения - это что, если () для! Если это делает поток управления Вашего метода слишком сложным, необходимо, вероятно, осуществить рефакторинг часть логики в отдельные методы - и затем могло бы иметь смысл иметь, они выдают исключение, которое ловит остающееся тело метода.

Однако я могу вообразить один особый случай, где могло иметь смысл бросать и ловить исключение в том же методе: когда Вы уже называете метод, который может выдать исключение и иметь блок выгоды для обработки его, затем в некоторых случаях могло иметь смысл выдавать исключение для указания на подобную проблему, которую существующий блок выгоды может решить таким же образом.

4
ответ дан 18 December 2019 в 05:17
поделиться

Я думаю, что Вы неправильно поняли первый случай. Обычно Вы добавляете блок выгоды попытки при вызове некоторого метода, который может выдать исключения. Ловля локально выдает исключения, действительно не имеет большого смысла. В особенности Вы не должны использовать исключения для выхода от циклов, поскольку это чрезвычайно медленно по сравнению со стандартным подходом.

6
ответ дан 18 December 2019 в 05:17
поделиться

Человек, который записал "это, не имеет никакого смысла выдавать исключение и затем ловить его в том же методе", имеется право их мнение, но это широко не совместно используется. Существует много случаев, где бросок и ловля исключения в том же методе - то, что необходимо. Самое простое - то, где Вы делаете последовательность операций, и отказ любого из них делает остальных недопустимыми. Если Вы обнаруживаете, что одна из этих операций перестала работать, совершенно разумно выдать исключение и поймать его в конце метода. На самом деле это - логический способ сделать вещи. Возможно Вы могли переписать код для не использования исключения, возможно, с некоторыми флагами состояния и оператором завершения или два, но почему будет Вы? Используя исключение проясняет, что идет и улучшает удобочитаемость кода.

3
ответ дан 18 December 2019 в 05:17
поделиться

Я собираюсь отвечать на Ваши вопросы в свою очередь, затем добавлять некоторые комментарии в конец. Я не полномочия на обработке исключений, но я надеюсь, что мои комментарии полезны.


"Не первый способ обработать исключения делает точно это"?

Мой ответ да, поскольку Вы описываете его, первый метод действительно работает путем броска и ловли исключения в том же методе. Однако я не знаю, что выгода броска попытки должна работать, поскольку Вы описываете ее.


"Я считал, что это - лучшая практика, чтобы выдать исключение в одном методе и поймать его в другом методе, но это - всего одно (вероятно, лучше) путь. Другой путь также законен и корректен, не так ли?"

Я соглашаюсь, что ловля исключений из второго метода лучше, но первый путь законен. Это корректно? хорошо это - чтобы Вы решили, это - Ваш код, в конце концов.

По большей части я соглашаюсь, что не имеет смысла выдавать исключение, затем сразу ловят то исключение в том же методе. Если мы делаем это, потому что метод особенно длинен/сложен и обрабатывает, ошибка с помощью другой логики усложнила бы вещи больше, то я предложу переместить часть этой логики к другому методу и назвать тот метод и поймать его исключение.

Если наш код более прост, то может быть легко обработать ошибку с помощью кода, который не состоит из выдачи исключения.


Мои комментарии:

Механизму выгоды броска попытки, который Вы упомянули, возможно, не понадобится исключение, которое будет брошено в тот же метод. Я должен был бы прочитать текст, который Вы нашли, чтобы быть бесспорными, но я буду ожидать, что это не необходимо. Если этому не было нужно исключение, которое будет брошено в тот же метод, то Вашими исключениями, обрабатывающими стратегию, является комбинация 2) 1) и 2).

В комбинации один метод использовал бы механизм выгоды броска попытки для ловли исключения, выданного вызываемым методом. Мне кажется, что 2) 1) и 2) должен сотрудничать для формирования стратегии обработки исключений.

Теперь, возможно, кто-то приедет и приведет нам некоторые замечательные причины, почему мы могли бы хотеть выдать исключение в том же методе. Я ожидаю, что существуют некоторые, но мне они кажутся исключениями, не правилом.

С наилучшими пожеланиями, Ed

3
ответ дан 18 December 2019 в 05:17
поделиться

Если Вы собираетесь вручную выдать исключение, то, очевидно, Вы знаете, что была некоторая ошибка, которая должна быть обработана. Вместо того, чтобы выдавать новое исключение, затем поймайте его, затем сразу обработайте ошибку, почему не только обрабатывают ошибку? Вы (и процессор) не должны проходить всю работу генерации исключения и ловли его. Исключение также делает код тяжелее, чтобы считать и отладить.

Вы выдали бы исключение, вместо того, чтобы просто сразу обработать ошибку, если:

  • Другой код, как код, который названный Вашим методом, должен обработать ошибку. Например, если Ваш код не является кодом UI, то он, вероятно, не должен генерировать окна. Это - Ваш метод № 2.

  • Можно использовать в своих интересах попытку, выгоду, наконец блок. Возможно, что Вы могли написать более чистый код этот путь, но я думаю, что 90% времени Ваш код были бы большим количеством читаемого использования, простого если операторы.

2
ответ дан 18 December 2019 в 05:17
поделиться

С первым путем делают Вы имеете в виду что-то вроде этого:

try {
  ok = doSomething();
  if (!ok) {
   throw new Exception("Error");
  }
 ok = doSomethingElse();
}catch (Exception e) {
}

Это позволит Вам выходить из блока try-catch, не выполняя остальную часть его. Это - единственное допустимое использование, я могу думать о выдаче исключения с броском и ловлей его самостоятельно в блоке try-catch. Однако стандарт, если блоки должны использоваться вместо этого. Я не понимаю, почему кто-то должен выдать исключение и затем поймать его сам.

Второй путь является более стандартным, особенно если вызывающая сторона метода, который выдает исключение, является внешним модулем. Это - способ сигнализировать, что что-то реальная несправедливость произошло. Это - обязанность вызывающей стороны обработать исключение.

2
ответ дан 18 December 2019 в 05:17
поделиться

Мой expierence - то, что использование первого метода получает Ваш код, быстро нечитабельный - начиная с функциональности, и обработка ошибок становится перепутанной. НО это имеет смысл в некоторых случаях, где у Вас есть попытка {} выгода {} наконец {} - например, в обработке файла или обработке базы данных, где Вы ALLWAYS хотите, чтобы соединение было закрыто.

try{ //do something
}catch(Exception ex){
//log
}finally{
//connection.close
}

Для всего остального я использую вторую опцию - только по причине централизовать мои процедуры обработки ошибок и сохранить удобочитаемость кода, реализовывая сам businesslogic.

1
ответ дан 18 December 2019 в 05:17
поделиться

По-моему, попробуйте блоки, которые Вы пишете, не должен включать "бросок, новый", которые пойманы в том же методе. При выдаче исключения Вы говорите, что "я встретился с ситуацией, что я не могу обработать; кто-то еще должен будет иметь дело с ним". Ваш метод с "броском, новым", должен или создать исключение непроверенное, чтобы бросить или объявить контролируемую исключительную ситуацию в ее сигнатуре метода.

При использовании сторонних классов, которые могут выдать исключения, метод должен иметь блок попытки/выгоды, если можно на самом деле обработать ситуацию, если исключение возникает. Иначе необходимо подчиниться другому классу, который может.

Я не создаю свое собственное исключение и затем ловлю его в том же методе.

1
ответ дан 18 December 2019 в 05:17
поделиться

С Используя исключение для потока управления конкретно имеет дело в Эффективном Java, 2-м Выпуске Joshua Bloch, Объект 57:

Объект 57: Используйте исключения только для исключительных условий

... исключения, поскольку их имя подразумевает, чтобы использоваться только для исключительных условий; они никогда не должны использоваться для обычного потока управления. [шахта курсива]

Таким образом, в то время как это, конечно, "работает" для использования исключений для потока управления, это не рекомендуется.

1
ответ дан 18 December 2019 в 05:17
поделиться

Причина, почему это казалось бы как ерунда (бросок и ловля в том же методе) состоит в том, потому что это было бы сценарием использования исключений для управления потоком. Если у Вас уже есть достаточно данных для идентификации условия, где исключение должно быть выдано затем, Вы могли использовать ту информацию для использования условия вместо этого.

Посмотрите ниже:

1) Бросок и ловля исключения в том же методе (неправильно)

public void method() { 
    try {    
        workA...
        workA...
        workA...
        workA...    
        if( conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) { 
            throw new IllegalStateException("No the rigth time" );
        }
        workB...
        workB...
        workB...
        workB...
    } catch( IllegalStateException iee ) { 
        System.out.println( "Skiped workB...");
    }
    workC....
    workC....
    workC....
    workC....
}

В этом сценарии бросок исключения используются для пропуска раздела "workB".

Это было бы лучше сделано как это:

2) Используя условие к потоку управления (справа)

public void method() { 
    workA...
    workA...
    workA...
    workA...    
    if( !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) ) { 
        //throw new IllegalStateException("No the rigth time" );
        workB...
        workB...
        workB...
        workB...

    }
    workC....
    workC....
    workC....
    workC....
}

И затем можно осуществить рефакторинг условие:

    if( !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() ) ) { 

для

    if( canProceedWithWorkB() ) {

реализованный как:

  boolean canProceedWithWorkB() {  
      return !(conditionIvalid() && notEnoughWhatever()  && isWrongMoment() );
  } 
0
ответ дан 18 December 2019 в 05:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: