Thursday, April 2, 2026

Python Exception Handling - try,except,finally

Errors are inevitable in programming, but Python provides a powerful way to manage them gracefully through exception handling. In this article we’ll see how to handle exceptions in Python using try, except and finally statements to avoid abrupt crashes and ensures proper cleanup.

How Python Exception Handling Works

To handle exception in Python you can use the following procedure-

  1. try block: Wraps code that may raise an exception.
  2. except block: Catches and handles specific raised exceptions.
  3. finally block (optional): Runs regardless of whether an exception was raised or not, often used for cleanup tasks like closing files or releasing resources.

General Syntax of exception handling in Python using try, except finally is as follows.

try: 
 # code that may raise an exception
               
except ExceptionType1:
 # handle ExceptionType1
except ExceptionType2:
 # handle ExceptionType2
else:
 # executes if no exception occurs
finally: 
 # always executes (cleanup code)

Some important points to note here are-

  1. You can have multiple except blocks to handle multiple exceptions.
  2. Else and finally blocks are not mandatory.
  3. If no exception is raised then the statements in the else block are executed.
  4. try block must be followed either by except or finally.
  5. If a finally block is present, it always executes, whether or not an exception is raised.

Using try, except for exception handling

Let’s try to understand how exception handling in Python using try and except helps in writing robust code. Here is an example where a list is passed to a function and every element in the list is used to divide a number. Just notice what happens if one of the number in the list is zero.

def divide_num(num_list):
  for num in num_list:
    print(10/num)

num_list = [5, 6, 0, 7]
divide_num(num_list)

Output

2.0
1.6666666666666667
Traceback (most recent call last):

  File "F:/NETJS/NetJS_2017/Python/Test/Test.py", line 6, in <module>
    divide_num(num_list)
  File "F:/NETJS/NetJS_2017/Python/Test/Test.py", line 3, in divide_num
    print(10/num)
ZeroDivisionError: division by zero

As you can see dividing by zero raises ZeroDivisionError, since code doesn’t provide any exception handling code of its own so default exception handling is used. Default behavior for handling such exceptions in Python is for the interpreter to print the full stack traceback, that includes the exception type (at least in case of built-in exception) and error message, and then terminate the program.

As you can see program is terminated and only the exception message is displayed by the default exception handling which is not that user friendly.

Python exception handling with try, except

Now let’s write that same code by providing exception handling with in the code using try and except.

def divide_num(num_list):
  for num in num_list:
    try:
      print(10/num)
    except ZeroDivisionError as error:
      print(error)
      print('Zero is not a valid argument here')
    else:
      print('in else block')

num_list = [5, 6, 0, 7]
divide_num(num_list)

Output

2.0
in else block
1.6666666666666667
in else block
division by zero
Zero is not a valid argument here
1.4285714285714286
in else block

As you can see now the code that may throw an exception is enclosed with in a try block. When the exception is raised in the try block exception handler looks for the except block that can handle the exception of that type.

In the try block, ZeroDivisionError is raised when dividing by zero. Since there is an except block that handles ZeroDivisionError, that block executes and gracefully handles the exception.

Program is not terminated now when the exception is raised because of the exception handling in the code.

except block in Python

There are various ways to write except block while writing exception handling code in Python.

  1. You can catch the exception as an object that gives description about the raised exception.
     except ZeroDivisionError as error:
     
  2. You can write except block with the exception class name only.
     except Exception_Class_Name:
     
  3. You can handle multiple exceptions by using multiple except blocks or you can use a single except block and write multiple exceptions as a tuple.

    For example multiple except blocks-

    except ZeroDivisionError as error:
      print(error)
      print('Zero is not a valid argument here')
    except TypeError:
      print('Argument is not of valid type') 
      

    Single except block with multiple exceptions

      except (ZeroDivisionError, TypeError):
      
  4. You can write except with out specifying exception class. That way except block catches any type of exception. Though that is not considered good practice as it is too broad exception clause and you won’t be able to determine specifically which exception has been raised.
      except:
        print('An exception has occurred')
      

Multiple except block Python example

def divide_num(num_list):
  for num in num_list:
    try:
      print(10/num)
    except ZeroDivisionError as error:
      print(error)
      print('Zero is not a valid argument here')
    except TypeError as error:
      print(error)
      print('Argument is not of valid type-', num)

num_list = [5, 6, 'a', 7]
divide_num(num_list)

Output

2.0
1.6666666666666667
unsupported operand type(s) for /: 'int' and 'str'
Argument is not of valid type- a
1.4285714285714286

finally in Python exception handling

If a finally block is present, it acts as a "cleanup" handler. The finally clause is always executed whether an exception is raised in the try block or not. This guarantees that important cleanup tasks, such as closing files, releasing database connections, or freeing resources are performed consistently.

def divide_num(num):
  try:
    f = open("testfile", "a")
    r = 10/num
    f.write("Result 10/%d is %d" %(num,r))
  except ZeroDivisionError as error:
    print(error)
    print('Zero is not a valid argument here')
  except FileNotFoundError as error:
    print(error)
    print('Passed file does not exist')

  finally:
    print('closing file')
    f.close()

divide_num(0)

Output

division by zero
Zero is not a valid argument here
closing file

If function is called with a valid argument and no exception is raised even then finally block is executed. For example calling function as given here.

divide_num(2)

Output

closing file

If there is a return, break or continue statement in try block even then finally clause is executed.

def divide_num():
  try:
    return 'try'
  finally:
    print('In finally clause')

a = divide_num()
print(a)

Output

In finally clause
try

If there is a return statement in finally too then that becomes the last return statement to be executed. Since the return value of a function is determined by the last return statement executed so value returned by finally clause is the value returned by the function.

def divide_num():
  try:
    return 'try'
  finally:
    print('In finally clause')
    return 'finally'

a = divide_num()
print(a)

Output

In finally clause
finally

That's all for this topic Python Exception Handling - try,except,finally. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Python Tutorial Page


Related Topics

  1. raise Statement in Python Exception Handling
  2. User-defined Exceptions in Python
  3. Passing Object of The Class as Parameter in Python
  4. Abstract Class in Python
  5. Strings in Python With Method Examples
  6. Python Generator, Generator Expression, Yield Statement

You may also like-

  1. Magic Methods in Python With Examples
  2. Check if String Present in Another String in Python
  3. Keyword Arguments in Python
  4. Python Program to Display Fibonacci Series
  5. Java Collections Interview Questions And Answers
  6. this Keyword in Java With Examples
  7. What is Hadoop Distributed File System (HDFS)
  8. Spring Object XML Mapping (OXM) JAXB Example

Python for Loop With Examples

In Python, loops allow you to execute a block of code repeatedly. The two primary looping constructs are the for..in loop and the while loop. In this tutorial, we’ll focus on the Python for loop with coding examples, which is most commonly used to iterate over sequences such as strings, lists, tuples, sets, or dictionaries.


Syntax of Python for loop

for var in sequence:
 #for loop body
else:
 #else_suite
  • The for loop iterates through each element in the given sequence one by one.
  • On every iteration, the current element is assigned to the variable var, and the loop body executes.
  • Python also provides an optional else clause with the for loop. The else block runs only if the loop completes all iterations without encountering a break statement.

for loop flow

Python for Loop

Python for loop examples

1- If you want to display characters of a String using for loop in Python.

str = 'Test'
for ch in str:
    print(ch)

Output

T
e
s
t

2- Iterating Over a List

cities = ['New York', 'London', 'Mumbai', 'Paris', 'Madrid']
for city in cities:
    print(city)

Output

New York
London
Mumbai
Paris
Madrid

for loop with range sequence type

The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.

Syntax of range is-

range([start,] stop[, step])

If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0.

1- Iterating 0..9 using range and for loop.

for i in range(10):
    print(i)

Output

0
1
2
3
4
5
6
7
8
9

Since start and step arguments are omitted in the range so by default step is 1 and start is 0.

2- Display odd numbers between 1 and 10 using range and for loop in Python.

for i in range(1, 10, 2):
    print(i)

Output

1
3
5
7
9

Here start argument is 1 and step is 2.

3- To display all the elements in a list using index.

Using len function you can get the total number of elements in the list which becomes an argument for range.

cities = ['New York', 'London', 'Mumbai', 'Paris', 'Madrid']
for i in range(len(cities)):
    print(cities[i])

Output

New York
London
Mumbai
Paris
Madrid

Python for loop with else statement

In Python for loop has an optional else statement too. If the for loop runs till completion and terminates the else-suite is executed.

If for loop doesn’t run completely because of any of the following reason, else statement is not executed.

  • for loop is terminated abruptly due to a break statement
  • for loop is terminated abruptly due to a return statement
  • if an exception is raised

Here is an example showing a scenario where for loop with else statement can come handy. If you want to implement a functionality to find an element in array. If element is found in the array then its index is returned otherwise -1 is returned.

In this scenario you can use else statement with python for loop. If an element is found you will return its index so else suite won’t be executed. If for loop runs till completion that would mean searched element is not found in the array in that case else suite is executed and -1 is returned.

from array import *
def find_in_array(array, value):
    for index, e in enumerate(array):
        if e == value:
            return index
    # else associated with for loop
    else:
        return -1

a = array('i', [3,4,5,6,7])
find_value = 4
index = find_in_array(a, find_value)
if index != -1:
    print(find_value, 'found in array at index', index)
else:
    print(find_value, 'not found in array')

Output

4 found in array at index 1

Nested for loop

for loop can be nested which means you can have one for loop inside another. In the nested loops for each iteration of the outer for loop, inner for loop is iterated for the given range of elements.

Python Nested for loop example

In the example a pyramid pattern using * is displayed using nested for loops.

rows = 6
for i in range (1, rows):
    for j in range (0, rows -i):
        #print spaces, end='' ensures control 
        # remains on the same line
        print(' ', end='')
    for k in range (0, i):
        print('* ', end='')
    print()

Output

     * 
    * * 
   * * * 
  * * * * 
 * * * * * 

Though in Python same pyramid pattern can be displayed very elegantly using a single for loop.

rows = 6
for i in range (1, rows):
    #repeat space for given times 
    print(' '*rows, end='')
    print('* '*(i))
    rows = rows -1

That's all for this topic Python for Loop With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Python Tutorial Page


Related Topics

  1. Python Conditional Statement - if, elif, else Statements
  2. Python return Statement With Examples
  3. Python break Statement With Examples
  4. Method Overriding in Python
  5. Name Mangling in Python

You may also like-

  1. Passing Object of The Class as Parameter in Python
  2. Nonlocal Keyword in Python With Examples
  3. String Slicing in Python
  4. Python Exception Handling Tutorial
  5. Association, Aggregation And Composition in Java
  6. Why Class Name And File Name Should be Same in Java
  7. Just In Time Compiler (JIT) in Java
  8. BeanFactoryPostProcessor in Spring Framework

Decision Tree Regression With Example

In this post we'll see how to use decision tree regression which uses decision trees for regression tasks to predict continuous values. Decision trees are also used for creating classification models to predict a category or class label.

How does decision tree regression work

In decision tree regressor, decision tree splits the data using features and threshold values that enables them to capture complex, non-linear relationships.

The decision tree regression model has a binary tree like structure where you have a-

  1. Root node- Starting point which represents the whole dataset.
  2. Decision nodes- A decision point where the algorithm chooses a feature and a threshold to split the data into subsets.
  3. Branches- From each decision node there are branches to child nodes, representing the outcome of the rule (tested decision). For example, if you have housing dataset and one of the features is square footage and the threshold value is 1500 then the algorithm at a decision node decides- Is square footage ≤ 1500
    • If yes go towards left (houses smaller than 1500 sft)
    • If no go towards right (houses larger than or equal to 1500 sft).
  4. Leaf node- Contains the final predicted value. Also known as the terminal node.
Decision Tree Structure
Decision Tree Structure

How is feature selected

If there are multiple features, at each node only one of the features is selected for making the decision rule but that feature is not just picked arbitrarily by the algorithm. All of the features are evaluated, where the steps are as given below-

  1. For each feature, the algorithm considers possible split points (threshold values).
  2. For each candidate split, the algorithm computes the decrease in impurity after splitting. For decision tree regressor, impurity is measured using one of the following metrics-
    • Mean Squared Error (MSE) which is the default
    • Friedman MSE
    • Mean Absolute Error (MAE)
    • Poisson deviance

    When splitting a parent node into left (L) and right (R) child nodes:

    $$Cost of (\mathrm{split})=C(L)+C(R)$$

    The algorithm evaluates all possible features and thresholds, and chooses the split that minimizes the total squared error across child nodes

    For a parent node with N samples split into-

    • Left child with N_L samples
    • Right child with N_R samples

    The cost of the split is-

    $$C(\mathrm{split})=\frac{N_L}{N}\cdot MSE(L)\; +\; \frac{N_R}{N}\cdot MSE(R)$$

    where-

    $$MSE(L)=\frac{1}{N_L}\sum _{i\in L}(y_i-\bar {y}_L)^2$$ $$MSE(R)=\frac{1}{N_R}\sum _{i\in R}(y_i-\bar {y}_R)^2$$
    • yi = target value of sample i
    • \(\bar {y}_L, \bar {y}_R\) = mean target values in left and right child nodes
    • \(N=N_L+N_R\)
  3. The same procedure is repeated recursively for each child node until stopping criteria are met (e.g., max depth, min samples per leaf, max_leaf_node or no further improvement). Which means at each node:
    • Compute cost of split (C-split) for all candidate features and thresholds.
    • Choose the split with the minimum cost of split

    Scikit-Learn uses the Classification and Regression Tree (CART) algorithm to train decision trees

Here is the decision tree structure (with max depth as 3) for the laptop data used in the example in this post.

Decision Tree

How is the value predicted

Before going to how prediction is done in decision tree regressor, note that by following the decision rules at each node, samples will ultimately fall into one of the leaf nodes. Value you see in each of the leaf node in the above image is the average of the target values of all the training samples that ended up in that specific leaf node.

To make a prediction for a new data point, you traverse the tree from the root to a leaf node by following the decision rules. If you follow the above image at the root node it has chosen the "TypeName" feature (actually that TypeName feature is encoded that's why you see the feature name as "encoder_type_notebook"), threshold value is 0.5. Same way for all the other decision nodes there are some rules which will be evaluated for the new data point and ultimately the new data point also falls into one of the leaf nodes. So, the predicted value for the new data point will be the value in that leaf node (the average of the target values of all the training samples that ended up in that specific leaf node).

Decision tree regression using scikit-learn Python library

Dataset used here can be downloaded from- https://www.kaggle.com/datasets/illiyask/laptop-dataset

Goal is to predict the price of the laptop based on the given features.

In the implementation code is broken into several smaller units with some explanation in between for the steps.

1. Importing libraries and reading CSV file

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
df = pd.read_csv('./laptop_eda.csv')

laptop_eda.csv file is in the current directory.

2. Getting info about the data.

df.describe(include='all')

Analyze the data, there are 1300 rows, price has lots of variance, minimum value is 9270.72 whereas maximum value is 324954.72.

3. Check for duplicates and missing values

#for duplicates
df.duplicated().value_counts()
#for missing values
df.isnull().sum()

Output (for duplicates)

False    1270
True       30
Name: count, dtype: int64

There are duplicates which can be removed.

df.drop_duplicates(inplace=True)

4. Plotting pairwise relationship in the dataset

sns.pairplot(df[["Company", "Ram", "Weight", "SSD", "Price"]], kind="reg")
plt.show()

This helps in understanding the relationship between features as well as with dependent variables.

Decision Tree Regression

If you analyse the plots, relationship between Price and RAM looks kind of linear otherwise it is non-linear relationship among the pairs.

5. Checking for outliers

To check for extreme values IQR method is used. The IQR (Interquartile Range) method detects outliers by finding data points falling below Q1 - 1.5 X IQR or above Q3 + 1.5 X IQR

Here IQR = Q3 - Q1 (middle 50% of data)

  • Q1 is the 25th percentile
  • Q3 is the 75th percentile
for label, content in df.select_dtypes(include='number').items():
    q1 = content.quantile(0.25)
    q3 = content.quantile(0.75)
    iqr = q3 - q1
    outl = content[(content <= q1 - 1.5 * iqr) | (content >= q3 + 1.5 * iqr)]
    perc = len(outl) * 100.0 / df.shape[0]
    print("Column %s outliers = %.2f%%" % (label, perc))

Output

Column Ram outliers = 17.24%
Column Weight outliers = 3.54%
Column Touchscreen outliers = 100.00%
Column ClockSpeed outliers = 0.16%
Column HDD outliers = 0.00%
Column SSD outliers = 1.42%
Column PPI outliers = 9.37%
Column Price outliers = 2.20%

Going back to where data info was displayed and analysing it shows RAM values are from 2 GB to 64 GB, which to me looks ok in the context of laptop dataset and doesn't require dropping of any rows.

Touchscreen has only 2 values 0 and 1 (binary column), so that also doesn't require deletion of any rows as outliers.

Price also has lots of variance. You can also plot a distplot to look for distribution.

dp = sns.displot(df['Price'], kde=True, bins=30)
dp.set(xlim=(0, None))

Plot shows positive skewness but in this example, not deleting any outliers for Price. You can test the final result by keeping all the rows or after deleting outliers.

6. Feature and label selection

X = df.iloc[:, :-1]
y = df.iloc[:, -1]

7. Checking for multicollinearity

Multicollinearity check is generally not required for decision tree regression. Decision trees split the data based on thresholds of individual features. They don't estimate coefficients like linear regression does, so correlated predictors don't distort parameter estimates.

8. Splitting and encoding data

Splitting is done using train_test_split where test_size is passed as 0.2, meaning 20% of the data is used as test data whereas 80% of the data is used to train the model.

from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

ct = ColumnTransformer([
    ('encoder', OneHotEncoder(sparse_output = False, drop = 'first', handle_unknown = 'ignore'), X.select_dtypes(exclude='number').columns)
],remainder = 'passthrough')

X_train_enc = ct.fit_transform(X_train)
X_test_enc = ct.transform(X_test)

9. Training the model and predicting values

from sklearn.tree import DecisionTreeRegressor
regressor = DecisionTreeRegressor(max_depth=5, random_state=42)
regressor.fit(X_train_enc, y_train)

y_pred = regressor.predict(X_test_enc)
df_result = pd.DataFrame({'Actual':y_test, 'Predicted':y_pred})
df_result.head(10)

Output (side-by-side comparison of actual values and predicted values)

	 	Actual		Predicted
1176	114731.5536	90147.685886
1117	69929.4672	60902.414400
427		106506.7200	60902.414400
351		75071.5200	60902.414400
364		20725.9200	27029.100706
853		41931.3600	55405.469087
1018	118761.1200	55405.469087
762		60153.1200	83108.137838
461		39906.7200	55405.469087
883		19660.3200	20666.681974

10. Seeing the model metrics such as R squared to check whether the model is overfitting or not.

from sklearn.metrics import r2_score, mean_squared_error
# for training data
print(regressor.score(X_train_enc, y_train))
#for predicted values
print(r2_score(y_test, y_pred))

Output

0.8003266191317047
0.7163190370541831

R2 score for training is 0.8 where as for test data it is 0.71

If the training score were very high (close to 1.0) and the test score much lower (like 0.3–0.4), that would indicate overfitting.

If both scores were low (say <0.5), that would indicate the model is too simple and not capturing the patterns.

The gap between 0.80 and 0.71 is modest. This means a slight overfitting, but not in extreme. The model generalizes reasonably well.

11. Plotting the tree

If you want to check how decision nodes were created by the algorithm you can plot the decision tree.

from sklearn.tree import plot_tree
plt.figure(figsize=(20,15)) 
plot_tree(regressor, filled=True, fontsize=10)
plt.show()

Another way to do it is by using the graphviz library. But that would mean downloading graphviz from this location- https://graphviz.org/download/

Also requires setting the path to the bin directory which can be done programmatically.

feature_names = ct.get_feature_names_out()
# get the name of the features used (after encoding)
X_train_final = pd.DataFrame(X_train_enc, columns=feature_names, index=X_train.index)

from sklearn.tree import export_graphviz
dot_data = export_graphviz(
regressor,
out_file=None,
feature_names=X_train_final.columns,
rounded=True,filled=True
)
import os
#setting path
os.environ["PATH"] += os.pathsep + r"D:\Softwares\Graphviz-14.1.1-win64\bin"
from graphviz import Source
Source(dot_data)

That's all for this topic Decision Tree Regression With Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Python Tutorial Page


Related Topics

  1. Simple Linear Regression With Example
  2. Multiple Linear Regression With Example
  3. Polynomial Regression With Example
  4. Support Vector Regression With Example
  5. Mean, Median and Mode With Python Examples

You may also like-

  1. Passing Object of The Class as Parameter in Python
  2. Local, Nonlocal And Global Variables in Python
  3. Python count() method - Counting Substrings
  4. Python Functions : Returning Multiple Values
  5. Marker Interface in Java
  6. Functional Interfaces in Java
  7. Difference Between Checked And Unchecked Exceptions in Java
  8. Race Condition in Java Multi-Threading

RunnableLambda in LangChain With Examples

RunnableLambda in LangChain is one of the core components of the LangChain Expression Language (LCEL). What RunnableLambda offers is that it can convert a Python (or JavaScript) function or a lambda expression into a Runnable object. This allows custom functions to be seamlessly integrated into the chain ecosystem of LangChain alongside other LangChain components like models, prompt templates, and retrievers.

LangChain RunnableLambda example

One of the prominent usecase depicting the usage of RunnableLambda is the implementation of routing in LangChain.

In LangChain there is a dedicated class called LLMRouterChain, which lets you use an LLM-powered chain to decide how inputs should be routed to different destinations. But this class is deprecated in latest versions. RunnableLambda is one of the way now for implementing routing as it provides several other benefits like streaming and batch support.

1. In the first example, we’ll have two chains, one which handles geography related queries and another which handles history related queries. Using RunnableLambda we can route to one of these chains based on whether the question is history based or geography based. That classification of the query is also done using the LLM. Note that Groq inference provider is used here which requires langchain-groq package installation and setting up the “GROQ_API_KEY” value.

from langchain_core.runnables import RunnableLambda
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_groq import ChatGroq
from typing_extensions import TypedDict
from operator import itemgetter
from typing import Literal

history_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a history expert."),
        ("human", "{query}"),
    ]
)
geography_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a geography expert."),
        ("human", "{query}"),
    ]
)

model = ChatGroq(model="qwen/qwen3-32b", temperature=0.5)

chain_history = history_prompt | model | StrOutputParser()
chain_geography = geography_prompt | model | StrOutputParser()

route_system = "Classify the user's query to either the history "
"or geography related. Answer with one word only: 'history' or 'geography'."
route_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", route_system),
        ("human", "{query}"),
    ]
)

#Class to enforce structured output from LLMs
class RouteQuery(TypedDict):
    """Schema for LLM output for routing queries."""
    destination: Literal["history", "geography"]

route_chain = (
    route_prompt
    | model.with_structured_output(RouteQuery)
    | itemgetter("destination")
)

final_chain = {
    "destination": route_chain,  
    "query": lambda x: x["query"],  # pass through input query
} | RunnableLambda(
    # if history, chain_history. otherwise, chain_geography.
    lambda x: (
        # display the routing decision for clarity
        print(f"Routing to destination: {x['destination']}") or
        (chain_history if x["destination"] == "history" else chain_geography)
    )
)

result = final_chain.invoke({"query": "List 5 temples built by the Cholas. Only list the temples, no other information. "})

print(result)

Output

Routing to destination: history
1. Brihadeeswara Temple, Thanjavur
2. Brihadeeswara Temple, Gangaikonda Cholapuram
3. Airavatesvara Temple, Darasuram
4. Nellaiappar Temple, Tirunelveli
5. Siva Temple, Kudavai

Points to note here:

  • The Literal type in Python from typing module, is a type hint that indicates a variable or function parameter must have one of a specific set of fixed, concrete values. Since the output of the LLM should be one of 'history' or 'geography' so that is enforced by passing these fixed values.
  • TypedDict is also used to enforce a structured output format.
  • The first part of the final chain
    {
        "destination": route_chain,  
        "query": lambda x: x["query"],  # pass through input query
    }
    
    is a dictionary that defines a mapping of inputs to outputs for the chain. The key "destination" will be populated by running route_chain.
  • In the second part of the chain, RunnableLambda wraps a lambda expression that selects the appropriate chain (chain_history or chain_geography) based on the "destination" value.

2. Second example also shows how to use RunnableLambda for routing. In the first example classification of the query is done by the LLM but in this one it is done by a Python function, which is wrapped into a RunnableLambda. Routing is done to one of the 3 agents based on the output of the Python function.

from langchain_core.runnables import RunnableLambda
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_ollama import ChatOllama

support_template = "You are a support agent. User input: {query}. Provide 3 reasons for the issue."
sales_template = "You are a sales specialist. User input: {query}. Provide 3 reasons to buy the product and 3 for not buying."
general_template = "You are a general assistant. User input: {query}. Provide a helpful response."
# 1. Define specialized chains
support_chain = ChatPromptTemplate.from_template(support_template) | ChatOllama(model="llama3.1") | StrOutputParser()
sales_chain = ChatPromptTemplate.from_template(sales_template) | ChatOllama(model="llama3.1") | StrOutputParser()
general_chain = ChatPromptTemplate.from_template(general_template) | ChatOllama(model="llama3.1") | StrOutputParser()

# 2. Define routing logic using RunnableLambda
def route_query(input: dict):
    print(f"Routing input: {input}")
    query = input["query"].lower()
    print(f"Routing query: {query}")
    if "support" in query or "issue" in query:
        return support_chain
    elif "price" in query or "buy" in query:
        return sales_chain
    else:
        return general_chain

router_node = RunnableLambda(route_query)

print("Router node created.", type(router_node))

# 3. Create the final routing chain
# The router_node returns a chain, which is then invoked with the input
final_chain = router_node 

# Example usage
result = final_chain.invoke({"query": "Request to buy a 3D printer."})

print(result)

Here’s what happens internally:

  • router_node runs route_query(input).
  • That function returns the right chain (support_chain, sales_chain, or general_chain).
  • Because router_node is a runnable, it automatically invokes the returned chain with the same input.

That's all for this topic RunnableLambda in LangChain With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. RunnableParallel in LangChain With Examples
  2. LangChain PromptTemplate + Streamlit - Code Generator Example
  3. Messages in LangChain
  4. Chain Using LangChain Expression Language With Examples

You may also like-

  1. String in Java Tutorial
  2. Array in Java
  3. Count Number of Words in a String Java Program
  4. Ternary Operator in Java With Examples
  5. Java Multithreading Interview Questions And Answers
  6. Java Exception Handling Tutorial
  7. ConcurrentHashMap in Java With Examples
  8. TreeMap in Java With Examples

Wednesday, April 1, 2026

Type Casting in Java With Conversion Examples

Type casting in Java is used to cast one type (primitive or object) to another type. Whenever you try to assign data of one type to variable of another type, type conversion happens in Java.

Types of Type Conversion in Java

Type conversion in Java may be classified into following four scenarios.

Out of these four; widening primitive type conversions and widening reference type conversions happen automatically. No explicit type casting is required.

In the case of narrowing primitive type conversions and narrowing reference conversions explicit type casting is required because they may lead to data loss or runtime exceptions.

Widening primitive conversions

If destination type (type to which you are converting) is larger than the source type, you are widening the type of your source type. For example, converting an int to a long or a float to a double. This type conversion will happen with out problem and automatically i.e. type casting is not required in this case.

As example-

int i = 10;
float f = i; // Assigning int to float

i which is an int can safely be assigned to float variable as float is compatible with int and also wider than int.

Widening reference conversions

Same way you can have a widening reference conversion. That is applicable in an inheritance scenario where a parent-child relationship exists.

For example if there is a parent class A and a child class B that extends class A then reference type A can safely hold reference type of class B.

A a;
B b = new B();
a = b; // Widening conversion from sub type to super type

Type casting in Java

Though automatic conversion is convenient and helpful, it may not always be possible. Especially in case of narrowing conversions. Narrowing conversion can be of two types-

  • Narrowing primitive conversions
  • Narrowing reference conversions

Narrowing primitive conversions

As the name suggests if you try to fit a value into a source that is narrower than the original type of the value then it is a narrowing conversion.

As example– If we do the exact opposite of what we did in the example of widening conversion and try to assign a float value to an int.

int i;
float f = 19.6f;
i = f; // Compile-time error (Type mismatch: cannot convert from float to int)

As you see, you get a compile-time error if you try to assign a float value to an int as it is a narrowing conversion. In case of narrowing conversion you need to explicitly type cast it to make it work.

General form of type casting in Java

(type) value;

Here type is the type to which the value has to be converted.

So in the above example we have to add an explicit cast to int.

Java type casting example

int i;
float f = 19.6f;
i = (int)f;
System.out.println("value " + i); 

Output

value 19

Here you can see that the fractional part is truncated.

Narrowing reference conversions

A super type can hold reference to an object of itself or the sub-types. But doing the opposite, when you want a conversion from super-type to sub-type, you will need type casting.

Since the conversion is from super-type to sub-type it is called narrowing reference conversion.

One important thing to always remember is; an object can only be type cast to its own class or one of its super-type, if you try to cast to any other object you may either get a compile-time error or a class-cast exception (run-time).

Narrowing reference conversion example

If we take the same example as used in widening reference conversion where there is a class A and a child class B that extends class A then reference type A can safely hold reference type of class B. But now we’ll try the opposite too.

A a;
B b = new B()
a = b; // OK widening conversion
b = a; // Compile-time error as it is a narrowing conversion

What you need to do to avoid compile-time error is-

b = (B)a;

Why type casting in Java required

You may have a scenario where child class has methods of its own apart from inheriting methods from the super class or overriding methods of the super class.

As a good programmer, you often design code to achieve polymorphism, holding a subclass object in a superclass reference. This allows flexibility and reusability. However, the limitation is that you can only call methods defined in the superclass. Any methods exclusive to the subclass remain inaccessible.

In order to call those methods you need casting to the type. Let’s try to understand it with an example.

Type casting Java example code

Here I have a class hierarchy where Payment is an interface and there are two classes CashPayment and CardPayment implementing the Payment interface.

Payment interface

public interface Payment {
 public boolean proceessPayment(double amount);
}

CashPayment class

import org.netjs.examples.interfaces.Payment;

public class CashPayment implements Payment {
 @Override
 public boolean proceessPayment(double amount) {
  System.out.println("Cash payment done for Rs. " + amount);
  return true;
 }
}

CardPayment class

import org.netjs.examples.interfaces.Payment;

public class CardPayment implements Payment {

 @Override
 public boolean proceessPayment(double amount) {
  System.out.println("Card Payment done for Rs. " + amount);
  return true;
 }
 
 public void printSlip(){
  System.out.println("Printing slip for payment" );
 }
}

In CardPayment class, note that, there is an extra method printSlip() which is exclusive to this class. Now when you do some payments using the class as given below-

import org.netjs.examples.interfaces.Payment;

public class PaymentDemo {
 public static void main(String[] args) {
  PaymentDemo pd = new PaymentDemo();
  Payment payment = new CashPayment();
  pd.doPayment(payment, 100);
  payment = new CardPayment();
  pd.doPayment(payment, 300);
  //int i = 10;
  //float f = i;
  
  int i;
  float f = 19.6f;
  i = (int)f;
  System.out.println("value " + i);
 }
 
 public void doPayment(Payment pd, int amt){
  pd.proceessPayment(amt);
  pd.printSlip();
 }
}

This method call pd.printSlip(); gives following compile-time error as the Payment object has no idea of the printSlip() method, thus the error-

The method printSlip() is undefined for the type Payment

If you want to call printSlip() method you need a cast back to CardPayment class type. Beware that there are two child classes and you don’t need that casting for CashPayment class object. Which means you need to use instanceof operator in conjunction with the casting.

Refer instanceof Operator in Java to know more about instanceof operator in Java.

With these corrections the code will now look like-

import org.netjs.examples.interfaces.Payment;

public class PaymentDemo {

 public static void main(String[] args) {
  PaymentDemo pd = new PaymentDemo();
  Payment payment = new CashPayment();
  pd.doPayment(payment, 100);
  payment = new CardPayment();
  pd.doPayment(payment, 300);
  //int i = 10;
  //float f = i;
  
  int i;
  float f = 19.6f;
  i = (int)f;
  System.out.println("value " + i);
 }
 
 public void doPayment(Payment pd, int amt){
  pd.proceessPayment(amt);
  
  if (pd instanceof CardPayment){
   CardPayment cardPay = (CardPayment)pd;
   cardPay.printSlip();
  }
 }
}

Output

Cash payment done for Rs. 100.0
Card Payment done for Rs. 300.0
Printing slip for payment
value 19

Here you can see how instanceof operator is used to make sure that the object is indeed of type CardPayment and then casting is done to the CardPayment type, which makes it possible to call the printSlip() method.

Reference: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html

That's all for this topic Type Casting in Java With Conversion Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Basics Tutorial Page


Related Topics

  1. Switch Case Statement in Java With Examples
  2. Access modifiers in Java
  3. Java pass by value or pass by reference
  4. Array in Java With Examples
  5. Java Exception Handling Tutorial

You may also like-

  1. Abstraction in Java
  2. Object Creation Using new Operator in Java
  3. static Import in Java With Examples
  4. Java Collections Interview Questions And Answers
  5. Java Multithreading Interview Questions And Answers
  6. Java Concurrency Interview Questions And Answers
  7. Race Condition in Java Multi-Threading
  8. Magic Methods in Python With Examples

Difference Between Abstract Class And Interface in Java

The difference between abstract class and interface in Java is one of the most common java interview questions, often asked right at the beginning to "break the ice". But that way Abstract class Vs Interface becomes a very important question as it is often said "first impression matters". So, understanding this topic thoroughly can set the tone for the rest of your interview.

First of all it is very important to know what an abstract class is and what an interface is. So please go through these two posts abstract class in Java and interface in Java to familiarize yourself with abstract class and interface.

There are also some similarities between abstract class and interface in Java like-

  • Both cannot be instantiated directly.
  • Both can declare abstract methods that must be implemented by subclasses (in case of abstract class) or implementing classes (in case of interface).

Abstract class Vs Interface in Java

Abstract Class Interface
Methods Abstract class can have both abstract methods (method with no body) and non-abstract methods (methods with implementation). Interface can have abstract methods only.
Note: From Java 8 interfaces can have default methods and static methods and private methods Java 9 onward. So on this account both abstract classes and interfaces in Java are becoming quite similar as both can have methods with implementation.
Access Modifiers Abstract class methods can have public, protected, private and default modifier apart from abstract methods. In interface, methods are by default public abstract only. From Java 9 private methods can also be added to a Java interface.
Variables Abstract class fields can be non-static or non-final. In interface all the fields are by default public, static, final.
Implementation Abstract class may have some methods with implementation and some methods as abstract. In interface all the methods are by default abstract, where only method signature is provided. Note: From Java 8 interfaces can have default methods where default implementation can be provided with in the interface and static methods that can be accessed using the Interface name. Apart from that interfaces can have private methods too Java 9 onward.
Constructor Abstract classes have a constructor, it may be user supplied or default in case no constructor is written by a user. Interfaces can't have a constructor.
Multiple Inheritance Abstract class can extend at most one class and implement one or more interfaces. Interface can only extend one or more interfaces.
Extends/Implements Abstract class are extended by the sub-classes. Sub-classes need to provide implementation for all the abstract methods of the extended abstract class or be declared as abstract itself. Interface is implemented by a class and the implementing class needs to provide implementation for all the abstract methods declared in an interface. If a class does not implement all the abstract methods of an interface then that class must be declared as abstract.
Easy to evolve Abstract class was considered easy to evolve as abstract classes could add new methods and provide default implementation to those methods. Interface was not considered easy to evolve as, in the case of adding new method to an interface, all the implementing classes had to be changed to provide implementation for the new method. With Java 8 even interfaces can have default methods so that issue has been addressed.

Which one should you use, abstract classes or interfaces?

As we know abstract classes have to be extended where as interfaces need to be implemented by a class. That itself suggests when to use what.

Abstract Class

Abstract classes are designed to be extended. They are ideal when you want to build a generalized base class and then provide specialized implementations by extending it. Abstract classes can hold state (fields), define constructors, and include both abstract and concrete methods. This makes them perfect for scenarios where you want to share common logic across related subclasses while still enforcing certain abstract behaviors.

Interface

Interfaces are meant to be implemented by unrelated classes. They define a contract that multiple classes can follow, each providing its own implementation. Since Java 8, interfaces can also include default methods and static methods, and from Java 9 onwards, even private methods for internal reuse. This evolution makes interfaces more powerful, but their primary role remains enabling polymorphism, the "one interface, multiple implementations” principle".

That's all for this topic Difference Between Abstract Class And Interface in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Basics Tutorial Page


Related Topics

  1. Interface in Java With Examples
  2. Marker Interface in Java
  3. Interface Static Methods in Java 8
  4. Interface Default Methods in Java 8
  5. Core Java Basics Interview Questions And Answers

You may also like-

  1. What are JVM, JRE and JDK in Java
  2. static Keyword in Java With Examples
  3. super Keyword in Java With Examples
  4. this Keyword in Java With Example
  5. Reflection in Java - Getting Class Information
  6. Autowiring using XML configuration in Spring
  7. How HashMap Works Internally in Java
  8. Count Number of Words in a String Java Program

Difference Between Array And ArrayList in Java

The difference between Array and ArrayList in Java is one question you may come across in Java technical interviews. While both structures are used to store data, they serve different purposes and have distinct characteristics. Understanding these differences is crucial for writing efficient and maintainable Java code

In this post we'll see some of the differences between ArrayList and Array in terms of how they are initialized and the performance they give.

Array Vs ArrayList in Java

  1. Fixed vs Dynamic Size
    Array: Once declared, an Array has a fixed size and cannot be resized. ArrayList: An ArrayList is dynamic, often referred to as a "dynamic array". ArrayList uses array of Object internally, but it has the logic to keep growing the size of the array as and when previous size is not able to fit in the number of elements stored in the ArrayList.

    Refer: How ArrayList works internally in Java to know more about the internal implementation of ArrayList.

  2. Data Types Stored
    Array: Can store both primitive types as well as objects.
    ArrayList: Can store only objects. With autoboxing and unboxing introduced in Java 5, primitives are automatically wrapped into their corresponding wrapper classes- (e.g., int -> Integer).

    For example, if you want an array of primitive type int-

    int[] intArray = new int[3];
    

    Or, if you have a class Employee and you want an array of size 5 to hold 5 Employee objects then-

    Employee[] employees = new Employee[5];
    

    In case of ArrayList if you want to store integers then you have to do this, note the use of wrapper class Integer-

    List<Integer> myList = new ArrayList<Integer>();
    
  3. Difference number 2 between array and ArrayList also indicates one more difference, which is about "type safety". Since Array knows the type of the data which it can hold so it will give compiler error "Type Mismatch" or "ArrayStoreException" if it is not able to resolve it at run time. For example following code throws ArrayStoreException.
    Object[] names = new String[3];
    names[0] = 12;
    
    Where as following code throws compile time error "Type Mismatch".
    String[] names = new String[3];
    names[0] = 12;
    

    In case of ArrayList, generics brought the much needed type safety which, as shown above, is not required for Array as type of elements stored in the array is specified at the array creation time itself, trying to store element of any other type will result in ArrayStoreException.

    If a list, which stores only Integers, is needed it should be defined as-

    List<Integer> myList = new ArrayList<Integer>();
    
  4. Performance Comparison
    Array: Since its size is fixed, there is no overhead of resizing. Memory usage is more efficient, especially when storing primitives, as they are not wrapped into objects.
    ArrayList: Internally backed by an array of objects, it offers dynamic resizing. When the internal array reaches capacity, a new larger array is created and elements are copied over, introducing overhead during expansion. Additionally, because ArrayList stores only objects, memory consumption is higher compared to arrays storing primitives
  5. Array has length variable which gives the length of the array. Note that length attribute denotes the length of the array at the time of declaration.
    For example, If an array is declared like this-
    String[] names = new String[3];
    names[0] = "Java";
    
    Then length var will always be 3 even if array names has only one value.

    In case of ArrayList, size() method is used and it will give the size as the current number of elements in the ArrayList.

That's all for this topic Difference Between Array And ArrayList in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Difference Between ArrayList And LinkedList in Java
  2. Difference Between ArrayList And Vector in Java
  3. Difference Between ArrayList And CopyOnWriteArrayList in Java
  4. HashSet Vs LinkedHashSet Vs TreeSet in Java
  5. Java Collections Interview Questions And Answers

You may also like-

  1. Difference Between Comparable and Comparator in Java
  2. Race condition in Java multi-threading
  3. Polymorphism in Java
  4. Method overriding in Java
  5. Merge Sort Program in Java
  6. Dependency Injection in Spring Framework
  7. What is LangChain - An Introduction
  8. List in Python With Examples